From 2e0912622bca412c0a1b1a3fdba30f65bf222ade Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Thu, 1 Jun 2000 20:59:21 +0000 Subject: [PATCH] =?utf8?q?ITS#537:=20lber=20io=20rewrite=20from=20Gambor?= =?utf8?q?=20Gombas.=20Copyright=202000=20G=C3=A1bor=20Gomb=C3=A1s.=20All?= =?utf8?q?=20rights=20reserved.=20This=20is=20free=20software.=20You=20may?= =?utf8?q?=20redistribute=20and=20use=20it=20under=20the=20same=20terms=20?= =?utf8?q?as=20OpenLDAP=20itself.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- include/lber.h | 98 ++- include/lber_pvt.h | 28 + libraries/liblber/dtest.c | 6 +- libraries/liblber/etest.c | 4 +- libraries/liblber/io.c | 31 +- libraries/liblber/lber-int.h | 140 +--- libraries/liblber/sockbuf.c | 1392 +++++++++++++++------------------- libraries/libldap/abandon.c | 2 +- libraries/libldap/cldap.c | 25 +- libraries/libldap/kbind.c | 2 +- libraries/libldap/ldap-int.h | 9 +- libraries/libldap/open.c | 41 +- libraries/libldap/options.c | 4 +- libraries/libldap/os-ip.c | 39 +- libraries/libldap/os-local.c | 2 +- libraries/libldap/request.c | 12 +- libraries/libldap/result.c | 11 +- libraries/libldap/sasl.c | 317 ++++++-- libraries/libldap/test.c | 11 +- libraries/libldap/tls.c | 373 ++++++--- libraries/libldap/unbind.c | 2 +- servers/ldapd/main.c | 18 +- servers/ldapd/request.c | 6 +- servers/ldapd/result.c | 6 +- servers/ldapd/search.c | 4 +- servers/slapd/connection.c | 96 ++- servers/slapd/result.c | 22 +- 27 files changed, 1465 insertions(+), 1236 deletions(-) diff --git a/include/lber.h b/include/lber.h index 515b45b19b..fb49db32b2 100644 --- a/include/lber.h +++ b/include/lber.h @@ -123,11 +123,26 @@ typedef struct lber_memory_fns { BER_MEMFREE_FN bmf_free; } BerMemoryFunctions; -/* LBER Sockbuf options */ -#define LBER_TO_FILE 0x01 /* to a file referenced by sb_fd */ -#define LBER_TO_FILE_ONLY 0x02 /* only write to file, not network */ -#define LBER_MAX_INCOMING_SIZE 0x04 /* impose limit on incoming stuff */ -#define LBER_NO_READ_AHEAD 0x08 /* read only as much as requested */ +/* LBER Sockbuf_IO options */ +#define LBER_SB_OPT_GET_FD 1 +#define LBER_SB_OPT_SET_FD 2 +#define LBER_SB_OPT_HAS_IO 3 +#define LBER_SB_OPT_SET_NONBLOCK 4 +#define LBER_SB_OPT_UDP_GET_SRC 5 +#define LBER_SB_OPT_UDP_SET_DST 6 +#define LBER_SB_OPT_GET_SSL 7 +#define LBER_SB_OPT_DATA_READY 8 +#define LBER_SB_OPT_SET_READAHEAD 9 +#define LBER_SB_OPT_DRAIN 10 +#define LBER_SB_OPT_NEEDS_READ 11 +#define LBER_SB_OPT_NEEDS_WRITE 12 +/* Largest option used by the library */ +#define LBER_SB_OPT_OPT_MAX 12 + +/* LBER IO operations stacking levels */ +#define LBER_SBIOD_LEVEL_PROVIDER 10 +#define LBER_SBIOD_LEVEL_TRANSPORT 20 +#define LBER_SBIOD_LEVEL_APPLICATION 30 /* get/set options for Sockbuf */ #define LBER_OPT_SOCKBUF_DESC 0x1000 @@ -145,6 +160,43 @@ typedef struct berelement BerElement; typedef struct sockbuf Sockbuf; typedef struct seqorset Seqorset; +typedef struct sockbuf_io Sockbuf_IO; + +/* Structure for LBER IO operarion descriptor */ +typedef struct sockbuf_io_desc { + int sbiod_level; + Sockbuf *sbiod_sb; + Sockbuf_IO *sbiod_io; + void *sbiod_pvt; + struct sockbuf_io_desc *sbiod_next; +} Sockbuf_IO_Desc; + +/* Structure for LBER IO operation functions */ +struct sockbuf_io { + int (*sbi_setup)( Sockbuf_IO_Desc *sbiod, void *arg ); + int (*sbi_remove)( Sockbuf_IO_Desc *sbiod ); + int (*sbi_ctrl)( Sockbuf_IO_Desc *sbiod, int opt, void *arg); + + ber_slen_t (*sbi_read)( Sockbuf_IO_Desc *sbiod, void *buf, + ber_len_t len ); + ber_slen_t (*sbi_write)( Sockbuf_IO_Desc *sbiod, void *buf, + ber_len_t len ); + + int (*sbi_close)( Sockbuf_IO_Desc *sbiod ); +}; + +/* Helper macros for LBER IO functions */ +#define LBER_SBIOD_READ_NEXT( sbiod, buf, len ) \ + ( (sbiod)->sbiod_next->sbiod_io->sbi_read( (sbiod)->sbiod_next, \ + buf, len ) ) +#define LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ) \ + ( (sbiod)->sbiod_next->sbiod_io->sbi_write( (sbiod)->sbiod_next, \ + buf, len ) ) +#define LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ) \ + ( (sbiod)->sbiod_next ? \ + ( (sbiod)->sbiod_next->sbiod_io->sbi_ctrl( \ + (sbiod)->sbiod_next, opt, arg ) ) : 0 ) + /* structure for returning a sequence of octet strings + length */ typedef struct berval { ber_len_t bv_len; @@ -428,16 +480,38 @@ ber_set_option LDAP_P(( * LBER sockbuf.c */ -LIBLBER_F( Sockbuf * ) -ber_sockbuf_alloc( void ); - LIBLBER_F( Sockbuf * ) -ber_sockbuf_alloc_fd( - ber_socket_t fd ); +ber_sockbuf_alloc LDAP_P(( + void )); LIBLBER_F( void ) -ber_sockbuf_free( - Sockbuf *sb ); +ber_sockbuf_free LDAP_P(( + Sockbuf *sb )); + +LIBLBER_F( int ) +ber_sockbuf_add_io LDAP_P(( + Sockbuf *sb, + Sockbuf_IO *sbio, + int layer, + void *arg )); + +LIBLBER_F( int ) +ber_sockbuf_remove_io LDAP_P(( + Sockbuf *sb, + Sockbuf_IO *sbio, + int layer )); + +LIBLBER_F( int ) +ber_sockbuf_ctrl LDAP_P(( + Sockbuf *sb, + int opt, + void *arg )); + +LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_tcp; +LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_udp; +LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_readahead; +LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_fd; +LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_debug; /* * LBER memory.c diff --git a/include/lber_pvt.h b/include/lber_pvt.h index 2a57ba11c6..e314205f47 100644 --- a/include/lber_pvt.h +++ b/include/lber_pvt.h @@ -20,6 +20,13 @@ LDAP_BEGIN_DECL +typedef struct sockbuf_buf { + ber_len_t buf_size; + ber_len_t buf_ptr; + ber_len_t buf_end; + char *buf_base; +} Sockbuf_Buf; + /* * bprint.c */ @@ -32,6 +39,27 @@ ber_pvt_log_printf LDAP_P(( const char *fmt, ... )) LDAP_GCCATTR((format(printf, 3, 4))); +/* + * sockbuf.c + */ +LIBLBER_F( ber_slen_t ) +ber_pvt_sb_do_write LDAP_P(( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )); + +LIBLBER_F( void ) +ber_pvt_sb_buf_init LDAP_P(( Sockbuf_Buf *buf )); + +LIBLBER_F( void ) +ber_pvt_sb_buf_destroy LDAP_P(( Sockbuf_Buf *buf )); + +LIBLBER_F( int ) +ber_pvt_sb_grow_buffer LDAP_P(( Sockbuf_Buf *buf, ber_len_t minsize )); + +LIBLBER_F( ber_len_t ) +ber_pvt_sb_copy_out LDAP_P(( Sockbuf_Buf *sbb, char *buf, ber_len_t len )); + +LIBLBER_F( int ) +ber_pvt_socket_set_nonblock LDAP_P(( ber_socket_t sd, int nb )); + LDAP_END_DECL #endif diff --git a/libraries/liblber/dtest.c b/libraries/liblber/dtest.c index 144445ece9..633d42ed7e 100644 --- a/libraries/liblber/dtest.c +++ b/libraries/liblber/dtest.c @@ -47,6 +47,7 @@ main( int argc, char **argv ) BerElement *ber; Sockbuf *sb; + int fd; /* enable debugging */ int ival = -1; @@ -62,7 +63,10 @@ main( int argc, char **argv ) cshow( stdout ); #endif - sb = ber_sockbuf_alloc_fd( fileno(stdin) ); + sb = ber_sockbuf_alloc(); + fd = fileno( stdin ); + ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, + (void *)&fd ); if( (ber = ber_alloc_t(LBER_USE_DER)) == NULL ) { perror( "ber_alloc_t" ); diff --git a/libraries/liblber/etest.c b/libraries/liblber/etest.c index 0dcf7d7111..01c10e9907 100644 --- a/libraries/liblber/etest.c +++ b/libraries/liblber/etest.c @@ -75,7 +75,9 @@ main( int argc, char **argv ) fd = fileno(stdout); #endif - sb = ber_sockbuf_alloc_fd( fd ); + sb = ber_sockbuf_alloc(); + ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, + (void *)&fd ); if( sb == NULL ) { perror( "ber_sockbuf_alloc_fd" ); diff --git a/libraries/liblber/io.c b/libraries/liblber/io.c index a31d23daf5..859b70c137 100644 --- a/libraries/liblber/io.c +++ b/libraries/liblber/io.c @@ -64,7 +64,7 @@ BerRead( assert( SOCKBUF_VALID( sb ) ); while ( len > 0 ) { - if ( (c = ber_pvt_sb_read( sb, buf, len )) <= 0 ) { + if ( (c = ber_int_sb_read( sb, buf, len )) <= 0 ) { if ( nread > 0 ) break; return( c ); @@ -232,26 +232,15 @@ ber_flush( Sockbuf *sb, BerElement *ber, int freeit ) if ( sb->sb_debug ) { ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug, "ber_flush: %ld bytes to sd %ld%s\n", towrite, - (long) sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)" - : "" ); + (long) sb->sb_fd, ber->ber_rwptr != ber->ber_buf ? + " (re-flush)" : "" ); ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug, ber->ber_rwptr, towrite ); } -#if HAVE_WRITE - if ( sb->sb_options & (LBER_TO_FILE | LBER_TO_FILE_ONLY) ) { - rc = write( sb->sb_fd, ber->ber_rwptr, towrite ); - if ( sb->sb_options & LBER_TO_FILE_ONLY ) { - if ( freeit ) - ber_free( ber, 1 ); - return( (int)rc ); - } - } -#endif - nwritten = 0; do { - rc = ber_pvt_sb_write( sb, ber->ber_rwptr, towrite ); + rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite ); if (rc<=0) { return -1; } @@ -446,7 +435,7 @@ get_tag( Sockbuf *sb ) assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 ) + if ( ber_int_sb_read( sb, (char *) &xbyte, 1 ) != 1 ) return( LBER_DEFAULT ); if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) @@ -455,7 +444,7 @@ get_tag( Sockbuf *sb ) tagp = (char *) &tag; tagp[0] = xbyte; for ( i = 1; i < sizeof(ber_tag_t); i++ ) { - if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 ) + if ( ber_int_sb_read( sb, (char *) &xbyte, 1 ) != 1 ) return( LBER_DEFAULT ); tagp[i] = xbyte; @@ -522,7 +511,7 @@ ber_get_next( if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag)) { if (ber->ber_rwptr == (char *) &ber->ber_tag) { - if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0) + if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0) return LBER_DEFAULT; if ((ber->ber_rwptr[0] & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK) { @@ -534,7 +523,7 @@ ber_get_next( } do { /* reading the tag... */ - if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0) + if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0) return LBER_DEFAULT; if (! (ber->ber_rwptr[0] & LBER_MORE_TAG_MASK) ) { ber->ber_tag>>=sizeof(ber->ber_tag) - @@ -550,7 +539,7 @@ ber_get_next( get_lenbyte: if (ber->ber_rwptr==(char *) &ber->ber_usertag) { unsigned char c; - if (ber_pvt_sb_read( sb, (char *) &c, 1)<=0) + if (ber_int_sb_read( sb, (char *) &c, 1)<=0) return LBER_DEFAULT; if (c & 0x80U) { int len = c & 0x7fU; @@ -611,7 +600,7 @@ fill_buffer: to_go = ber->ber_end - ber->ber_rwptr; assert( to_go > 0 ); - res = ber_pvt_sb_read( sb, ber->ber_rwptr, to_go ); + res = ber_int_sb_read( sb, ber->ber_rwptr, to_go ); if (res<=0) return LBER_DEFAULT; ber->ber_rwptr+=res; diff --git a/libraries/liblber/lber-int.h b/libraries/liblber/lber-int.h index 10b8b2cbd7..70d10c0447 100644 --- a/libraries/liblber/lber-int.h +++ b/libraries/liblber/lber-int.h @@ -28,15 +28,15 @@ LIBLBER_F (BER_ERRNO_FN) ber_int_errno_fn; struct lber_options { short lbo_valid; + unsigned short lbo_options; + int lbo_debug; +}; + #define LBER_UNINITIALIZED 0x0 #define LBER_INITIALIZED 0x1 #define LBER_VALID_BERELEMENT 0x2 #define LBER_VALID_SOCKBUF 0x3 - unsigned short lbo_options; - int lbo_debug; -}; - LIBLBER_F (struct lber_options) ber_int_options; #define ber_int_debug ber_int_options.lbo_debug @@ -62,106 +62,21 @@ struct berelement { }; #define BER_VALID(ber) ((ber)->ber_valid==LBER_VALID_BERELEMENT) - #define ber_pvt_ber_bytes(ber) ((ber)->ber_ptr - (ber)->ber_buf) #define ber_pvt_ber_remaining(ber) ((ber)->ber_end - (ber)->ber_ptr) -struct sockbuf; - -struct sockbuf_io { - int (*sbi_setup)( struct sockbuf * sb, void *arg ); - int (*sbi_remove)( struct sockbuf *sb ); - - ber_slen_t (*sbi_read)( struct sockbuf *sb, void *buf, ber_len_t len ); - ber_slen_t (*sbi_write)( struct sockbuf *sb, void *buf, ber_len_t len ); - int (*sbi_close)( struct sockbuf *sb ); -}; - -struct sockbuf_sec { - int (*sbs_setup)( struct sockbuf * sb, void *arg ); - int (*sbs_remove)( struct sockbuf *sb ); - - long (*sbs_protect)( struct sockbuf *sb, char *in, long *ilen, - char *out, long olen ); - long (*sbs_release)( struct sockbuf *sb, char *in, long ilen, - char *out0, long olen0, char *out1, long olen1 ); -}; - -struct sockbuf_buf { - ber_len_t buf_size; - ber_len_t buf_ptr; - ber_len_t buf_end; - char *buf_base; -}; - -typedef struct sockbuf_io Sockbuf_IO; -typedef struct sockbuf_sec Sockbuf_Sec; -typedef struct sockbuf_buf Sockbuf_Buf; - -LIBLBER_F( Sockbuf_IO ) ber_pvt_sb_io_tcp; -LIBLBER_F( Sockbuf_IO ) ber_pvt_sb_io_udp; - - struct sockbuf { struct lber_options sb_opts; + Sockbuf_IO_Desc *sb_iod; /* I/O functions */ #define sb_valid sb_opts.lbo_valid #define sb_options sb_opts.lbo_options #define sb_debug sb_opts.lbo_debug - - int sb_non_block:1; - int sb_read_ahead:1; - - int sb_buf_ready:1; - int sb_trans_ready:1; - int sb_sec_ready:1; - - /* these bits indicate if the transport layer - * needs to read or write - */ + ber_socket_t sb_fd; int sb_trans_needs_read:1; int sb_trans_needs_write:1; - - int sb_fd; - - void *sb_iodata; /* transport-layer data pointer */ - Sockbuf_IO *sb_io; /* I/O functions */ - -#ifdef LDAP_SASL - void *sb_sdata; /* security-layer data pointer */ - Sockbuf_Sec *sb_sec; -#endif - - ber_socket_t sb_sd; - -#ifdef DEADWOOD - long sb_max_incoming; -#endif - Sockbuf_Buf sb_buf; -#ifdef LDAP_SASL - Sockbuf_Buf sb_sec_buf_in; - Sockbuf_Buf sb_sec_buf_out; - ber_len_t sb_sec_prev_len; -#endif }; -#define SOCKBUF_VALID(ber) ((sb)->sb_valid==LBER_VALID_SOCKBUF) -/* these should be internal ie: ber_int_* */ -#define ber_pvt_sb_get_desc( sb ) ((sb)->sb_sd) -#define ber_pvt_sb_set_desc( sb, val ) ((sb)->sb_sd =(val)) - -#define ber_pvt_sb_in_use( sb ) ((sb)->sb_sd != AC_SOCKET_INVALID) - -#ifdef USE_SASL -#define ber_pvt_sb_data_ready( sb ) \ -(((sb)->sb_buf_ready) || ((sb)->sb_trans_ready) || ((sb)->sb_sec_ready)) -#else -#define ber_pvt_sb_data_ready( sb ) \ -(((sb)->sb_buf_ready) || ((sb)->sb_trans_ready)) -#endif -#define ber_pvt_sb_needs_read( sb ) \ -((sb)->sb_trans_needs_read) -#define ber_pvt_sb_needs_write( sb ) \ -((sb)->sb_trans_needs_write) +#define SOCKBUF_VALID( sb ) ( (sb)->sb_valid == LBER_VALID_SOCKBUF ) #define READBUFSIZ 8192 @@ -245,51 +160,20 @@ LIBLBER_F (BerMemoryFunctions *) ber_int_memory_fns; /* sockbuf.c */ -/* these should be ber_int*() functions */ - -LIBLBER_F( int ) -ber_pvt_sb_init LDAP_P(( Sockbuf *sb )); - LIBLBER_F( int ) -ber_pvt_sb_destroy LDAP_P(( Sockbuf *sb )); +ber_int_sb_init LDAP_P(( Sockbuf *sb )); -#ifdef USE_SASL LIBLBER_F( int ) -ber_pvt_sb_set_sec LDAP_P(( Sockbuf *sb, Sockbuf_Sec *sec, void *arg )); - -LIBLBER_F( int ) -ber_pvt_sb_clear_sec LDAP_P(( Sockbuf *sb )); -#endif +ber_int_sb_close LDAP_P(( Sockbuf *sb )); LIBLBER_F( int ) -ber_pvt_sb_set_io LDAP_P(( Sockbuf *sb, Sockbuf_IO *layer, void *arg )); - -LIBLBER_F( int ) -ber_pvt_sb_clear_io LDAP_P(( Sockbuf *sb )); - -LIBLBER_F( int ) -ber_pvt_sb_close LDAP_P((Sockbuf *sb )); - -LIBLBER_F( int ) -ber_pvt_sb_set_nonblock LDAP_P(( Sockbuf *sb, int nb )); - -LIBLBER_F( int ) -ber_pvt_sb_set_readahead LDAP_P(( Sockbuf *sb, int rh )); +ber_int_sb_destroy LDAP_P(( Sockbuf *sb )); LIBLBER_F( ber_slen_t ) -ber_pvt_sb_read LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len )); +ber_int_sb_read LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len )); LIBLBER_F( ber_slen_t ) -ber_pvt_sb_write LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len )); - -LIBLBER_F( int ) -ber_pvt_sb_udp_set_dst LDAP_P((Sockbuf *sb, void *addr )); - -LIBLBER_F( void * ) -ber_pvt_sb_udp_get_src LDAP_P((Sockbuf *sb )); - -LIBLBER_F( int ) -ber_pvt_socket_set_nonblock LDAP_P(( ber_socket_t sd, int nb )); +ber_int_sb_write LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len )); LDAP_END_DECL diff --git a/libraries/liblber/sockbuf.c b/libraries/liblber/sockbuf.c index 2b9bb8799a..5cdda86ad9 100644 --- a/libraries/liblber/sockbuf.c +++ b/libraries/liblber/sockbuf.c @@ -29,630 +29,266 @@ #include "lber-int.h" -#ifdef LDAP_TEST -#undef TEST_PARTIAL_READ -#undef TEST_PARTIAL_WRITE -#endif - -#define MAX_BUF_SIZE 65535 -#define MIN_BUF_SIZE 4096 - -#define sockbuf_io_write( sb, buf, len ) \ -((sb)->sb_io->sbi_write( (sb), (buf), (len) )) +#define MIN_BUFF_SIZE 4096 +#define MAX_BUFF_SIZE 65536 +#define DEFAULT_READAHEAD 16384 -#define sockbuf_io_read( sb, buf, len ) \ -((sb)->sb_io->sbi_read( (sb), (buf), (len) )) +Sockbuf * +ber_sockbuf_alloc( void ) +{ + Sockbuf *sb; -static ber_slen_t have_no_read( Sockbuf *sb, void *buf, ber_len_t len ); -static ber_slen_t have_no_write( Sockbuf *sb, void *buf, ber_len_t len ); -static int have_no_close( Sockbuf *sb ); + ber_int_options.lbo_valid = LBER_INITIALIZED; -static Sockbuf_IO sb_IO_None= -{ - NULL, /* sbi_setup */ - NULL, /* sbi_release */ - have_no_read, /* sbi_read */ - have_no_write, /* sbi_write */ - have_no_close /* sbi_close */ -}; + sb = LBER_CALLOC( 1, sizeof( Sockbuf ) ); -static void -update_status( Sockbuf *sb ) -{ - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + if( sb == NULL ) + return NULL; - sb->sb_buf_ready = (sb->sb_buf.buf_ptr < sb->sb_buf.buf_end); -#ifdef USE_SASL - sb->sb_sec_ready = ((sb->sb_sec_buf_in.buf_end!=0) && - (sb->sb_sec_buf_in.buf_ptr >= - sb->sb_sec_buf_in.buf_end)); -#endif + ber_int_sb_init( sb ); + return sb; } -#ifdef LDAP_DEBUG -static int -status_is_ok( Sockbuf *sb ) +void +ber_sockbuf_free( Sockbuf *sb ) { - int obr; -#ifdef USE_SASL - int osr; -#endif - assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - obr = sb->sb_buf_ready; -#ifdef USE_SASL - osr = sb->sb_sec_ready; -#endif - - update_status(sb); - if (obr!=sb->sb_buf_ready) - return 0; - -#ifdef USE_SASL - if (osr!=sb->sb_sec_ready) - return 0; -#endif - - return 1; + ber_int_sb_close( sb ); + ber_int_sb_destroy( sb ); + LBER_FREE( sb ); } -#endif -#ifdef USE_SASL -static ber_len_t -packet_length( Sockbuf *sb, const char *buf ) +/* Return values: -1: error, 0: no operation performed or the answer is false, + * 1: successful operation or the answer is true + */ +int +ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg ) { - ber_len_t size; + Sockbuf_IO_Desc *p; + int ret = 0; + char buf[4096]; - assert( buf != NULL ); + assert( sb != NULL ); - size = (((ber_len_t)buf[0])<<24)| - (((ber_len_t)buf[1])<<16)| - (((ber_len_t)buf[2])<<8)| - (((ber_len_t)buf[3])); - - if ( size > MAX_BUF_SIZE ) { - /* somebody is trying to mess me up. */ - ber_log_printf( LDAP_DEBUG_SASL, sb->sb_debug, - "SASL: received packet length of %lu bytes\n", - (unsigned long) size ); - size = 16; /* this should lead to an error. */ + switch ( opt ) { + case LBER_SB_OPT_HAS_IO: + p = sb->sb_iod; + + while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) + p = p->sbiod_next; + + if ( p ) + ret = 1; + break; + case LBER_SB_OPT_GET_FD: + if ( arg != NULL ) + *((int *)arg) = sb->sb_fd; + ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1); + break; + case LBER_SB_OPT_SET_FD: + sb->sb_fd = *((int *)arg); + ret = 1; + break; + case LBER_SB_OPT_SET_NONBLOCK: + ret = ( ber_pvt_socket_set_nonblock( sb->sb_fd, + (int)arg ) ? -1 : 1 ); + break; + case LBER_SB_OPT_DRAIN: + /* Drain the data source to enable possible errors (e.g. + * TLS) to be propagated to the upper layers + */ + do { + ret = ber_int_sb_read( sb, buf, sizeof( buf ) ); + } while ( ret == sizeof( buf ) ); + + ret = 1; + break; + case LBER_SB_OPT_NEEDS_READ: + ret = ( sb->sb_trans_needs_read ? 1 : 0 ); + break; + case LBER_SB_OPT_NEEDS_WRITE: + ret = ( sb->sb_trans_needs_write ? 1 : 0 ); + break; + default: + ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, + opt, arg ); + break; } - - return size + 4; /* include the size !!! */ -} -#endif - -static int -grow_buffer( Sockbuf_Buf * buf, ber_len_t minsize ) -{ - ber_len_t pw;; - - assert( buf != NULL ); - for( pw=MIN_BUF_SIZE; pw MAX_BUF_SIZE) { - /* this could mean that somebody is trying to crash us. */ - return -1; - } - } - minsize = pw; - - if (buf->buf_sizebuf_base==NULL) || ((buf->buf_end==0) && (buf->buf_ptr==0))) { - /* empty buffer */ - if (buf->buf_base!=NULL) - LBER_FREE( buf->buf_base ); - assert( buf->buf_ptr==0 ); - assert( buf->buf_end==0 ); - buf->buf_base = LBER_MALLOC( minsize ); - if (buf->buf_base==NULL) - return -1; - } else { - char *nb; - nb = LBER_REALLOC( buf->buf_base, minsize ); - if (nb==NULL) - return -1; - buf->buf_base = nb; - } - buf->buf_size = minsize; - } - return 0; + return ret; } -#ifdef USE_SASL -static ber_slen_t -sockbuf_sec_release( Sockbuf *sb, char *buf, ber_len_t len ) +int +ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg ) { - /* when this is called: - * sb->sb_sec_buf_in.buf_base points to a packet. - * sb->sb_sec_buf_in.buf_ptr contains the total bytes read. - * sb->sb_sec_end.buf_end contains the packet length. - * - * sb->sb_buf.buf_ptr == sb->sb_buf.buf_end == 0; - */ - long rlen; - long total; - char *ptr; - char *end; - long size; + Sockbuf_IO_Desc *d, *p, **q; - assert( buf != NULL ); assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - - assert( sb->sb_sec ); - assert( sb->sb_sec->sbs_release ); - assert( sb->sb_sec_buf_in.sb_ptr >= sb->sb_sec_buf_in.sb_end ); - - assert( sb->sb_buf.sb_ptr == 0 ); - assert( sb->sb_buf.sb_end == 0 ); - - assert( status_is_ok(sb) ); - total = 0; + if ( sbio == NULL ) + return -1; - ptr = sb->sb_sec_buf_in.buf_base; - end = ptr+ sb->sb_sec_buf_in.buf_ptr; - size = sb->sb_sec_buf_in.buf_end; + q = &sb->sb_iod; + p = *q; + while ( p && p->sbiod_level > layer ) { + q = &p->sbiod_next; + p = *q; + } - sb->sb_sec_ready = 1; + d = LBER_MALLOC( sizeof( *d ) ); + if ( d == NULL ) + return -1; - for(;(ptr+size<=end);) { - for(;;) { - rlen = sb->sb_sec->sbs_release( sb, ptr, size, - buf, len, - sb->sb_buf.buf_base, - sb->sb_buf.buf_size ); - if (rlen==0) { - /* this means a security violation. */ - return total; /* total ? total : 0 */ - } - if (rlen<0) { - /* this means that the buffer isn't big enough. */ - if (grow_buffer( &(sb->sb_buf), -rlen )<0) - /* memory violation. */ - return total; /* total ? total : 0 */ - continue; - } - /* if (rlen>0) */ - break; - } - total+=rlen; - - /* move to the next packet... */ - ptr+=size; + d->sbiod_level = layer; + d->sbiod_sb = sb; + d->sbiod_io = sbio; + memset( &d->sbiod_pvt, 0, sizeof( d->sbiod_pvt ) ); + d->sbiod_next = p; + *q = d; - if (ptr+4<=end) - size = packet_length( sb, ptr ); - /* size is always at least 4, so the loop condition is always OK !!*/ - assert( size>=4 ); + if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) + return -1; - if (rlensb_buf_ready = (sb->sb_buf.buf_end = rlen - len) ? 1 : 0; - break; - } + return 0; } - if (ptr+size>end) - sb->sb_sec_ready = 0; - /* clean up the mess. */ - if (ptrsb_sec_buf_in.buf_base, ptr, end-ptr ); - sb->sb_sec_buf_in.buf_ptr = 0; - sb->sb_sec_buf_in.buf_end -= (ptr - sb->sb_sec_buf_in.buf_base); - } - assert( status_is_ok(sb) ); - return total; -} - -static long -sockbuf_sec_protect( Sockbuf *sb, char *buf, long len ) +int +ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer ) { - long ret; - long blen; - long total; - - assert( buf != NULL ); + Sockbuf_IO_Desc *p, **q; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - - assert( sb->sb_sec_out.buf_end == 0 ); - assert( sb->sb_sec_out.buf_ptr == 0 ); - - assert( sb->sb_sec ); - assert( sb->sb_sec->sbs_protect ); - assert( status_is_ok(sb) ); - - total = 0; - for(;(len);) { - for(;;) { - blen = len; - ret = sb->sb_sec->sbs_protect( sb, buf, &blen, - sb->sb_sec_out.buf_base+ - sb->sb_sec_out.buf_end, - sb->sb_sec_out.buf_size - - sb->sb_sec_out.buf_end ); - if (ret==0) - /* protection error ? */ - return total; - if (ret<0) { - if (grow_buffer( &(sb->sb_sec_out),-ret-sb->sb_sec_out.buf_end )<0) - /* memory error */ - return total; - continue; - } - /* else if (ret>0) */ + if ( sb->sb_iod == NULL ) + return -1; + + q = &sb->sb_iod; + while ( *q != NULL ) { + p = *q; + if ( layer == p->sbiod_level && p->sbiod_io == sbio ) { + if ( p->sbiod_io->sbi_remove != NULL && + p->sbiod_io->sbi_remove( p ) < 0 ) + return -1; + *q = p->sbiod_next; + LBER_FREE( p ); break; - } - sb->sb_sec_out.buf_end += ret; - len -= blen; - total += blen; } - assert( status_is_ok(sb) ); - return total; + q = &p->sbiod_next; } -#endif - -static ber_len_t -sockbuf_copy_out( Sockbuf *sb, char **buf, ber_len_t len ) -{ - ber_len_t blen = (sb->sb_buf.buf_end - sb->sb_buf.buf_ptr ); - assert( buf != NULL ); - - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - - if (blen) { - ber_len_t rlen = (blensb_buf.buf_base + sb->sb_buf.buf_ptr, rlen ); - sb->sb_buf.buf_ptr+=rlen; - *buf+=rlen; - len -= rlen; - if (sb->sb_buf.buf_ptr >= sb->sb_buf.buf_end) { - sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0; - sb->sb_buf_ready = 0; - } else { - sb->sb_buf_ready = 1; - } - } - assert( status_is_ok(sb) ); - return len; + return 0; } -Sockbuf *ber_sockbuf_alloc( void ) +void +ber_pvt_sb_buf_init( Sockbuf_Buf *buf ) { - Sockbuf *sb; - - ber_int_options.lbo_valid = LBER_INITIALIZED; - - sb = LBER_CALLOC(1, sizeof(Sockbuf)); - - if( sb == NULL ) return NULL; - - ber_pvt_sb_init( sb ); - return sb; + buf->buf_base = NULL; + buf->buf_ptr = 0; + buf->buf_end = 0; + buf->buf_size = 0; } -Sockbuf *ber_sockbuf_alloc_fd( ber_socket_t fd ) +void +ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf ) { - Sockbuf *sb = ber_sockbuf_alloc(); - - if( sb == NULL ) return NULL; - - ber_pvt_sb_set_desc( sb, fd ); - ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); - return sb; -} + assert( buf != NULL); -void ber_sockbuf_free( Sockbuf *sb ) -{ - assert(sb != NULL); - assert( SOCKBUF_VALID( sb ) ); - ber_pvt_sb_destroy( sb ); - LBER_FREE(sb); + if (buf->buf_base) + LBER_FREE( buf->buf_base ); + ber_pvt_sb_buf_init( buf ); } -ber_slen_t -ber_pvt_sb_read( Sockbuf *sb, void *buf_arg, ber_len_t len ) +int +ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize ) { - char *buf; - ber_slen_t ret; + ber_len_t pw; + char *p; - assert( buf_arg != NULL ); - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - - /* slapd might have problems with this */ - assert( ber_pvt_sb_in_use( sb ) ); + assert( buf != NULL ); -#ifdef TEST_PARTIAL_READ - if ((rand() & 3)==1) { /* 1 out of 4 */ - errno = EWOULDBLOCK; + for ( pw = MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) { + if (pw > MAX_BUFF_SIZE) return -1; } - if( len > 0 ) - len = (rand() % len)+1; -#endif - - buf = (char *) buf_arg; - - if (sb->sb_buf.buf_ptr!=sb->sb_buf.buf_end) { - len = sockbuf_copy_out( sb, &buf, len ); - if (len==0) { - return (buf - (char *) buf_arg); - } + if ( buf->buf_size < pw ) { + p = LBER_REALLOC( buf->buf_base, pw ); + if ( p == NULL ) + return -1; + buf->buf_base = p; + buf->buf_size = pw; } - -#ifdef USE_SASL - if (sb->sb_sec) { - ber_slen_t max; - assert( sb->sb_sec->sbs_release ); - assert( sb->sb_sec_buf_in.buf_base ); - if (sb->sb_read_ahead) { - max = sb->sb_sec_buf_in.buf_size - sb->sb_sec_buf_in.buf_ptr; - } else { - max = sb->sb_sec_buf_in.buf_end - sb->sb_sec_buf_in.buf_ptr; - if (max<=0) { - /* special situation. This means that we need to read the first - * four bytes for the packet length. - */ - max += 4; - } - } - for(;;) { - /* read from stream into sb_sec_buf_in */ - for(;;) { - ret = sockbuf_io_read( sb, sb->sb_sec_buf_in.buf_base + - sb->sb_sec_buf_in.buf_ptr, max ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; - } - if (ret<=0) { - /* read error. return */ - goto do_return; - } - sb->sb_sec_buf_in.buf_ptr += ret; - - if (sb->sb_sec_buf_in.buf_ptr < sb->sb_sec_buf_in.buf_end) { - /* did not finish a packet. give up. */ - goto do_return; - } - - if (sb->sb_sec_buf_in.buf_end == 0) { - /* Were trying to read the first four bytes... */ - if (sb->sb_sec_buf_in.buf_ptr < 4) { - /* did not read enough for packet length. give up. */ - goto do_return; - } - /* calculate the packet length. */ - sb->sb_sec_buf_in.buf_end = - packet_length(sb, sb->sb_sec_buf_in.buf_base ); - if ((sb->sb_sec_buf_in.buf_end > sb->sb_sec_buf_in.buf_size) && - (grow_buffer( &(sb->sb_sec_buf_in), sb->sb_sec_buf_in.buf_end)<0)) { - /* buffer has to be to big. exit with error. */ - ret = -1; - goto do_return; - } - if (sb->sb_sec_buf_in.buf_ptr >= sb->sb_sec_buf_in.buf_end) { - /* finished packet. decode it. */ - goto decode_packet; - } - /* did not finish packet yet. try again ? */ - if (sb->sb_read_ahead) { - /* we were trying to read the max anyway. forget it */ - goto do_return; - } - } -decode_packet: - /* we read enough for at least 1 packet */ - ret = sockbuf_sec_release( sb, buf, len ); - if (ret<=0) { - /* something went wrong... */ - goto do_return; - } - buf+=ret; - len-=ret; - /* we are finished !!! */ - if ((len==0) || (ret!=max)) - goto do_return; - } - } else { -#endif - if (sb->sb_read_ahead) { - ber_slen_t max; - max = sb->sb_buf.buf_size - sb->sb_buf.buf_end; - if (max> (ber_slen_t) len) { - for(;;) { - ret = sockbuf_io_read( sb, - sb->sb_buf.buf_base + - sb->sb_buf.buf_end, - max ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; - } - if (ret<=0) { - /* some error occured */ - goto do_return; - } - sb->sb_buf.buf_end += ret; - /* move out the data... */ - len = sockbuf_copy_out( sb, &buf, len ); - goto do_return; - } - } - /* no read_ahead, just try to put the data in the buf. */ - for(;;) { - ret = sockbuf_io_read( sb, buf, len ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; - } - if (ret>0) { - buf+=ret; - len-=ret; - } - /* we might as well return, since there is nothing to do... */ -#ifdef USE_SASL - } -#endif -do_return: - assert( status_is_ok(sb) ); - if ((ret<=0) && (buf==buf_arg)) { - /* there was an error. */ - return ret; - } - return (buf - ((char *) buf_arg)); + return 0; } -#ifdef USE_SASL -long sockbuf_do_write( Sockbuf *sb ) +ber_len_t +ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len ) { - long to_go; - ber_slen_t ret; + ber_len_t max; - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - - to_go = sb->sb_sec_out.buf_end - sb->sb_sec_out.buf_ptr; - assert( to_go > 0 ); - /* there is something left of the last time... */ - for(;;) { - ret = sockbuf_io_write( sb, sb->sb_sec_out.buf_base+ - sb->sb_sec_out.buf_ptr, to_go ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; + assert( buf != NULL ); + assert( sbb != NULL ); + assert( sbb->buf_size > 0 ); + + max = sbb->buf_end - sbb->buf_ptr; + max = ( max < len) ? max : len; + if ( max ) { + memcpy( buf, sbb->buf_base + sbb->buf_ptr, max ); + sbb->buf_ptr += max; + if ( sbb->buf_ptr >= sbb->buf_end ) + sbb->buf_ptr = sbb->buf_end = 0; } - if (ret<=0) /* error */ - return ret; - sb->sb_sec_out.buf_ptr += ret; - if (retsbiod_sb ) ); - len_arg = (rand() % len_arg)+1; - len = len_arg; -#endif + to_go = buf_out->buf_end - buf_out->buf_ptr; + assert( to_go > 0 ); -#ifdef USE_SASL - if (sb->sb_sec) { - assert( sb->sb_sec_prev_len <= len ); - if (sb->sb_sec_prev_len) { - ret = sockbuf_do_write( sb ); - if (ret<=0) - return ret; - /* finished. */ - len -= sb->sb_sec_prev_len; - sb->sb_sec_prev_len = 0; - sb->sb_sec_out.buf_end = sb->sb_sec_out.buf_ptr = 0; - } - /* now protect the next packet. */ - ret = sockbuf_sec_protect( sb, buf, len ); - if (ret<=0) - return ret; - ret = sockbuf_do_write( sb ); - if (ret<=0) { - sb->sb_sec_prev_len = len; - return ret; - } - return len_arg; - } else { -#endif for(;;) { - ret = sockbuf_io_write( sb, buf, len ); + ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base + + buf_out->buf_ptr, to_go ); #ifdef EINTR if ((ret<0) && (errno==EINTR)) continue; #endif break; } -#ifdef USE_SASL - } -#endif + if ( ret <= 0 ) return ret; -} - -int ber_pvt_sb_close( Sockbuf *sb ) -{ - int ret; - - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io ); - assert( sb->sb_io->sbi_close ); - assert( status_is_ok(sb) ); - assert( ber_pvt_sb_in_use( sb ) ); - ret = sb->sb_io->sbi_close( sb ); - ber_pvt_sb_set_desc( sb, -1 ); - + buf_out->buf_ptr += ret; + if (buf_out->buf_ptr == buf_out->buf_end) + buf_out->buf_end = buf_out->buf_ptr = 0; + if ( ret < to_go ) + /* not enough data, so pretend no data was sent. */ + return -1; return ret; } -int ber_pvt_sb_set_readahead( Sockbuf *sb, int rh ) -{ - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - sb->sb_read_ahead = (rh!=0); - return 0; -} - -int ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) +int +ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) { #if HAVE_FCNTL - int flags = fcntl(ber_pvt_sb_get_desc(sb), F_GETFL); - if( nb ) { + int flags = fcntl( sd, F_GETFL); + if( nb ) flags |= O_NONBLOCK; - } else { + else flags &= ~O_NONBLOCK; - } - return fcntl( ber_pvt_sb_get_desc(sb), F_SETFL, flags ); + return fcntl( sd, F_SETFL, flags ); #elif defined( FIONBIO ) ioctl_t status = nb ? 1 : 0; @@ -660,201 +296,100 @@ int ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) #endif } -#define USE_NONBLOCK -#ifdef USE_NONBLOCK -int ber_pvt_sb_set_nonblock( Sockbuf *sb, int nb ) -{ - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - if (nb) { - sb->sb_non_block = 1; -#if 0 - sb->sb_read_ahead = 1; -#endif - } else { - sb->sb_non_block = 0; -#if 0 - sb->sb_read_ahead = 0; -#endif - } - if (ber_pvt_sb_in_use(sb)) { - return ber_pvt_socket_set_nonblock( - ber_pvt_sb_get_desc(sb), nb ); - } - return 0; -} -#endif - -#define sockbuf_buf_init( bb ) do { \ - Sockbuf_Buf *sbb = (bb); \ - sbb->buf_base = NULL; \ - sbb->buf_ptr = 0; \ - sbb->buf_end = 0; \ - sbb->buf_size = 0; \ - } while(0) - -static int -sockbuf_buf_destroy( Sockbuf_Buf *buf ) -{ - assert( buf != NULL); - - if (buf->buf_base) - LBER_FREE( buf->buf_base ); - sockbuf_buf_init( buf ); - return 0; -} - -int ber_pvt_sb_init( Sockbuf *sb ) +int +ber_int_sb_init( Sockbuf *sb ) { assert( sb != NULL); - ber_int_options.lbo_valid = LBER_INITIALIZED; - sb->sb_valid=LBER_VALID_SOCKBUF; sb->sb_options = 0; - sb->sb_debug = 0; - sb->sb_trans_ready = 0; - sb->sb_buf_ready = 0; -#ifdef USE_SASL - sb->sb_sec_ready = 0; -#endif - sb->sb_read_ahead = 1; /* test */ - sb->sb_non_block = 0; + sb->sb_debug = ber_int_debug; + sb->sb_fd = AC_SOCKET_INVALID; + sb->sb_iod = NULL; sb->sb_trans_needs_read = 0; sb->sb_trans_needs_write = 0; - sb->sb_fd = -1; - sb->sb_iodata = NULL; - sb->sb_io = &sb_IO_None; - sb->sb_sd = -1; -#ifdef DEADWOOD - sb->sb_max_incoming = 0; -#endif - sockbuf_buf_init( &(sb->sb_buf) ); -#ifdef USE_SASL - sockbuf_buf_init( &(sb->sb_sec_buf_in) ); - sockbuf_buf_init( &(sb->sb_sec_buf_out) ); - sb->sb_sdata = NULL; - sb->sb_sec = NULL; - sb->sb_sec_prev_len = 0; -#endif assert( SOCKBUF_VALID( sb ) ); return 0; } -int ber_pvt_sb_destroy( Sockbuf *sb ) +int +ber_int_sb_close( Sockbuf *sb ) { - assert( sb != NULL); - assert( SOCKBUF_VALID(sb) ); -#ifdef USE_SASL - ber_pvt_sb_clear_sec(sb); - sockbuf_buf_destroy( &(sb->sb_sec_buf_in) ); - sockbuf_buf_destroy( &(sb->sb_sec_buf_out) ); -#endif - ber_pvt_sb_clear_io(sb); - sockbuf_buf_destroy( &(sb->sb_buf) ); - return ber_pvt_sb_init( sb ); -} + Sockbuf_IO_Desc *p; -#ifdef USE_SASL -int ber_pvt_sb_set_sec( Sockbuf *sb, Sockbuf_Sec * sec, void *arg ) -{ - int len; assert( sb != NULL); - assert( SOCKBUF_VALID( *sb ) ); - if ((sb->sb_sec) || (sec==NULL)) - return -1; - - sb->sb_sec = sec; - if ((sec->sbs_setup) && (sec->sbs_setup( sb, arg)<0)) { + p = sb->sb_iod; + while ( p ) { + if ( p->sbiod_io->sbi_close && + p->sbiod_io->sbi_close( p ) < 0 ) return -1; + p = p->sbiod_next; } - len = sb->sb_buf.buf_end - sb->sb_buf.buf_ptr; + sb->sb_fd = AC_SOCKET_INVALID; - if (len>0) { - /* move this to the security layer. */ - if (grow_buffer( &(sb->sb_sec_buf_in), len )<0) - return -1; - memcpy( sb->sb_sec_buf_in.buf_base, - sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, len ); - sb->sb_sec_buf_in.buf_ptr = len; - sb->sb_sec_buf_in.buf_end = (len>4) ? packet_length( sb, sb->sb_sec_buf_in ) : 0; - sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0; - } - update_status( sb ); return 0; } -int ber_pvt_sb_clear_sec( Sockbuf *sb ) +int +ber_int_sb_destroy( Sockbuf *sb ) { + Sockbuf_IO_Desc *p; + assert( sb != NULL); assert( SOCKBUF_VALID( sb ) ); - - if (sb->sb_buf.buf_ptr!=0) - return -1; - if (sb->sb_sec==NULL) - return -1; - if ((sb->sb_sec->sbs_remove) && (sb->sb_sec->sbs_remove(sb)<0)) - return -1; - - sb->sb_sec = NULL; - if (sb->sb_sec_buf_in.buf_ptr!=0) { - if (grow_buffer( &(sb->sb_buf), - sb->sb_buf.buf_end + sb->sb_sec_buf_in.buf_ptr)<0) - return -1; - memcpy( sb->sb_buf.buf_base + sb->sb_buf.buf_end, - sb->sb_sec_buf_in.buf_base, sb->sb_sec_buf_in.buf_ptr ); - sb->sb_buf.buf_end += sb->sb_sec_buf_in.buf_ptr; - sb->sb_buf_ready = 1; - } - sockbuf_buf_destroy( &(sb->sb_sec_buf_in) ); - assert( sb->sb_sec_buf.buf_end==0 ); - sockbuf_buf_destroy( &(sb->sb_sec_buf_out) ); - sb->sb_sec_ready = 0; - - return 0; + while ( sb->sb_iod ) { + p = sb->sb_iod->sbiod_next; + ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io, + sb->sb_iod->sbiod_level ); + sb->sb_iod = p; +} + return ber_int_sb_init( sb ); } -#endif -int ber_pvt_sb_set_io( Sockbuf *sb, Sockbuf_IO *trans, void *arg ) +ber_slen_t +ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len ) { + ber_slen_t ret; + + assert( buf != NULL ); assert( sb != NULL); + assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io == &sb_IO_None ); - if (trans==NULL) - return -1; - - sb->sb_io = trans; - - if ((trans->sbi_setup) && (trans->sbi_setup( sb, arg)<0)) - return -1; - - return 0; + for (;;) { + ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) + continue; +#endif + break; +} + return ret; } -int ber_pvt_sb_clear_io( Sockbuf *sb ) +ber_slen_t +ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len ) { + ber_slen_t ret; + + assert( buf != NULL ); assert( sb != NULL); + assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); - if (sb->sb_io==&sb_IO_None) - return -1; - - if ((sb->sb_io->sbi_remove) && (sb->sb_io->sbi_remove( sb )<0)) - return -1; - - sb->sb_io = &sb_IO_None; - - sb->sb_trans_ready = 0; - sb->sb_trans_needs_read = 0; - sb->sb_trans_needs_write = 0; - - return 0; + for (;;) { + ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) + continue; +#endif + break; +} + return ret; } /* @@ -862,16 +397,16 @@ int ber_pvt_sb_clear_io( Sockbuf *sb ) */ static ber_slen_t -stream_read( Sockbuf *sb, void *buf, ber_len_t len ) +sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ - return tcpread( ber_pvt_sb_get_desc(sb), 0, (unsigned char *)buf, + return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf, len, NULL ); #elif defined( HAVE_PCNFS ) || \ @@ -887,7 +422,8 @@ stream_read( Sockbuf *sb, void *buf, ber_len_t len ) */ { int rc; - rc = recv( ber_pvt_sb_get_desc(sb), buf, len, 0 ); + + rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); #ifdef HAVE_WINSOCK if ( rc < 0 ) @@ -905,26 +441,25 @@ stream_read( Sockbuf *sb, void *buf, ber_len_t len ) /* * NCSA Telnet TCP/IP stack (under DOS) */ - return nread( ber_pvt_sb_get_desc(sb), buf, len ); + return nread( sbiod->sbiod_sb->sb_fd, buf, len ); #else - return read( ber_pvt_sb_get_desc(sb), buf, len ); + return read( sbiod->sbiod_sb->sb_fd, buf, len ); #endif } static ber_slen_t -stream_write( Sockbuf *sb, void *buf, ber_len_t len ) +sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ #define MAX_WRITE 65535 - return tcpwrite( ber_pvt_sb_get_desc(sb), - (unsigned char *)(buf), + return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf, (lensbiod_sb->sb_fd, buf, len, 0 ); #ifdef HAVE_WINSOCK if ( rc < 0 ) { int err; + err = WSAGetLastError(); errno = err; } @@ -954,36 +491,53 @@ stream_write( Sockbuf *sb, void *buf, ber_len_t len ) } #elif defined(HAVE_NCSA) - return netwrite( ber_pvt_sb_get_desc(sb), buf, len ); + return netwrite( sbiod->sbiod_sb->sb_fd, buf, len ); #elif defined(VMS) /* * VMS -- each write must be 64K or smaller */ #define MAX_WRITE 65535 - return write( ber_pvt_sb_get_desc(sb), buf, + return write( sbiod->sbiod_sb->sb_fd, buf, (lensbiod_sb->sb_fd, buf, len ); #endif } static int -stream_close( Sockbuf *sb ) +sb_stream_close( Sockbuf_IO_Desc *sbiod ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); - tcp_close( ber_pvt_sb_get_desc( sb ) ); + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + tcp_close( sbiod->sbiod_sb->sb_fd ); return 0; } -Sockbuf_IO ber_pvt_sb_io_tcp= +/* The argument is a pointer to the socket descriptor */ +static int +sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { + assert( sbiod != NULL ); + + if ( arg != NULL ) + sbiod->sbiod_sb->sb_fd = *((int *)arg); + return 0; +} + +static int +sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { + /* This is an end IO descriptor */ + return 0; +} + +Sockbuf_IO ber_sockbuf_io_tcp = { - NULL, /* sbi_setup */ - NULL, /* sbi_release */ - stream_read, /* sbi_read */ - stream_write, /* sbi_write */ - stream_close, /* sbi_close */ + sb_stream_setup, /* sbi_setup */ + NULL, /* sbi_remove */ + sb_stream_ctrl, /* sbi_ctrl */ + sb_stream_read, /* sbi_read */ + sb_stream_write, /* sbi_write */ + sb_stream_close /* sbi_close */ }; /* @@ -997,53 +551,52 @@ struct dgram_data }; static int -dgram_setup( Sockbuf *sb, void *arg ) +sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + struct dgram_data *p; + + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); - sb->sb_iodata = LBER_MALLOC( sizeof( struct dgram_data ) ); - if (sb->sb_iodata==NULL) + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) return -1; - sb->sb_read_ahead = 1; /* important since udp is packet based. */ + memset( p, 0, sizeof( *p ) ); + sbiod->sbiod_pvt = (void *)p; + if ( arg != NULL ) + sbiod->sbiod_sb->sb_fd = *((int *)arg); return 0; } static int -dgram_release( Sockbuf *sb ) +sb_dgram_release( Sockbuf_IO_Desc *sbiod ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); - LBER_FREE( sb->sb_iodata ); + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; return 0; } static ber_slen_t -dgram_read( Sockbuf *sb, void *buf, ber_len_t len ) +sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { #ifdef LDAP_CONNECTIONLESS ber_slen_t rc; socklen_t addrlen; - struct dgram_data *dd; + struct dgram_data *p; - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( buf != NULL ); - dd = (struct dgram_data *)(sb->sb_iodata); + p = (struct dgram_data *)sbiod->sbiod_pvt; addrlen = sizeof( struct sockaddr ); - rc=recvfrom( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen ); + rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->src, + &addrlen ); - if ( sb->sb_debug ) { - ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug, - "dgram_read udp_read %ld bytes\n", - (long) rc ); - if ( rc > 0 ) - ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug, - buf, rc ); - } return rc; # else /* LDAP_CONNECTIONLESS */ return -1; @@ -1051,30 +604,30 @@ dgram_read( Sockbuf *sb, void *buf, ber_len_t len ) } static ber_slen_t -dgram_write( Sockbuf *sb, void *buf, ber_len_t len ) +sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { #ifdef LDAP_CONNECTIONLESS ber_slen_t rc; - struct dgram_data *dd; + struct dgram_data *p; - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( buf != NULL ); - dd = (struct dgram_data *)(sb->sb_iodata); + p = (struct dgram_data *)sbiod->sbiod_pvt; - rc=sendto( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst), + rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->dst, sizeof( struct sockaddr ) ); if ( rc <= 0 ) - return( -1 ); + return -1; /* fake error if write was not atomic */ if (rc < len) { # ifdef EMSGSIZE errno = EMSGSIZE; # endif - return( -1 ); + return -1; } return rc; #else @@ -1083,84 +636,325 @@ dgram_write( Sockbuf *sb, void *buf, ber_len_t len ) } static int -dgram_close( Sockbuf *sb ) +sb_dgram_close( Sockbuf_IO_Desc *sbiod ) { - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); - tcp_close( ber_pvt_sb_get_desc(sb) ); + tcp_close( sbiod->sbiod_sb->sb_fd ); return 0; } -Sockbuf_IO ber_pvt_sb_io_udp= +static int +sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { - dgram_setup, /* sbi_setup */ - dgram_release, /* sbi_release */ - dgram_read, /* sbi_read */ - dgram_write, /* sbi_write */ - dgram_close, /* sbi_close */ + struct dgram_data *p; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct dgram_data *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_UDP_SET_DST ) { + memcpy( &p->dst, arg, sizeof( struct sockaddr ) ); + return 1; + } + else if ( opt == LBER_SB_OPT_UDP_GET_SRC ) { + *(( struct sockaddr **)arg) = &p->src; + return 1; + } + /* This is an end IO descriptor */ + return 0; +} + +Sockbuf_IO ber_sockbuf_io_udp = +{ + sb_dgram_setup, /* sbi_setup */ + sb_dgram_release, /* sbi_release */ + sb_dgram_ctrl, /* sbi_ctrl */ + sb_dgram_read, /* sbi_read */ + sb_dgram_write, /* sbi_write */ + sb_dgram_close /* sbi_close */ }; -int ber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr ) +/* + * Support for readahead (UDP needs it) + */ + +static int +sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { - struct dgram_data *dd; - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io == &ber_pvt_sb_io_udp ); - dd = (struct dgram_data *) (sb->sb_iodata); - memcpy( &(dd->dst), addr, sizeof( struct sockaddr ) ); + Sockbuf_Buf *p; + + assert( sbiod != NULL ); + + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) + return -1; + ber_pvt_sb_buf_init( p ); + if ( arg == NULL ) + ber_pvt_sb_grow_buffer( p, DEFAULT_READAHEAD ); + else + ber_pvt_sb_grow_buffer( p, *((int *)arg) ); + sbiod->sbiod_pvt = p; return 0; } -void *ber_pvt_sb_udp_get_src( Sockbuf *sb ) +static int +sb_rdahead_remove( Sockbuf_IO_Desc *sbiod ) { - struct dgram_data *dd; + Sockbuf_Buf *p; - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io == &ber_pvt_sb_io_udp ); - dd = (struct dgram_data *) (sb->sb_iodata); - return &(dd->src); + assert( sbiod != NULL ); + + p = (Sockbuf_Buf *)sbiod->sbiod_pvt; + + if ( p->buf_ptr != p->buf_end ) + return -1; + + ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) ); + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; + + return 0; } +static ber_slen_t +sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) +{ + Sockbuf_Buf *p; + ber_slen_t bufptr = 0, ret, max; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + assert( sbiod->sbiod_next != NULL ); + + p = (Sockbuf_Buf *)sbiod->sbiod_pvt; + + assert( p->buf_size > 0 ); + + /* Are there anything left in the buffer? */ + ret = ber_pvt_sb_copy_out( p, buf, len ); + bufptr += ret; + len -= ret; + + if ( len == 0 ) + return bufptr; + + max = p->buf_size - p->buf_end; + ret = 0; + while ( max > 0 ) { + ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end, + max ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) + continue; +#endif + break; +} + + if ( ret < 0 ) + return ( bufptr ? bufptr : ret ); + + p->buf_end += ret; + bufptr += ber_pvt_sb_copy_out( p, buf + bufptr, len ); + return bufptr; +} + +static ber_slen_t +sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) +{ + assert( sbiod != NULL ); + assert( sbiod->sbiod_next != NULL ); + + return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); +} + +static int +sb_rdahead_close( Sockbuf_IO_Desc *sbiod ) +{ + assert( sbiod != NULL ); + + /* Just erase the buffer */ + ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt); + return 0; +} + +static int +sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + Sockbuf_Buf *p; + + p = (Sockbuf_Buf *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_DATA_READY ) { + if ( p->buf_ptr != p->buf_end ) + return 1; + } + else if ( opt == LBER_SB_OPT_SET_READAHEAD ) { + if ( p->buf_size >= *((ber_len_t *)arg) ) + return 0; + return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ? + -1 : 1 ); + } + + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +Sockbuf_IO ber_sockbuf_io_readahead = +{ + sb_rdahead_setup, /* sbi_setup */ + sb_rdahead_remove, /* sbi_remove */ + sb_rdahead_ctrl, /* sbi_ctrl */ + sb_rdahead_read, /* sbi_read */ + sb_rdahead_write, /* sbi_write */ + sb_rdahead_close /* sbi_close */ +}; + /* - * debug routines. - * - * BUGS: - * These routines should really call abort, but at the moment that would - * break the servers. + * Support for simple file IO */ static ber_slen_t -have_no_read( Sockbuf *sb, void *buf, ber_len_t len ) +sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); - ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug, - "warning: reading from uninitialized sockbuf\n"); - errno = EBADF; - return -1; + return read( sbiod->sbiod_sb->sb_fd, buf, len ); } static ber_slen_t -have_no_write( Sockbuf *sb, void *buf, ber_len_t len ) +sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); - ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug, - "warning: writing to uninitialized sockbuf\n"); - errno = EBADF; - return -1; + return write( sbiod->sbiod_sb->sb_fd, buf, len ); } static int -have_no_close( Sockbuf *sb ) +sb_fd_close( Sockbuf_IO_Desc *sbiod ) { - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + close( sbiod->sbiod_sb->sb_fd ); + return 0; +} + +/* The argument is a pointer to the file descriptor */ +static int +sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { + assert( sbiod != NULL ); + + if ( arg != NULL ) + sbiod->sbiod_sb->sb_fd = *((int *)arg); + return 0; +} + +static int +sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { + /* This is an end IO descriptor */ + return 0; +} + +Sockbuf_IO ber_sockbuf_io_fd = +{ + sb_fd_setup, /* sbi_setup */ + NULL, /* sbi_remove */ + sb_fd_ctrl, /* sbi_ctrl */ + sb_fd_read, /* sbi_read */ + sb_fd_write, /* sbi_write */ + sb_fd_close /* sbi_close */ +}; + +/* + * Debugging layer + */ - assert( 0 ); +static int +sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg ) +{ + assert( sbiod != NULL ); + + if ( arg == NULL ) + arg = "sockbuf_"; + + sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 ); + if ( sbiod->sbiod_pvt == NULL ) return -1; + strcpy( (char *)sbiod->sbiod_pvt, (char *)arg ); + return 0; } + +static int +sb_debug_remove( Sockbuf_IO_Desc *sbiod ) +{ + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; + return 0; +} + +static int +sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +static ber_slen_t +sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) +{ + ber_slen_t ret; + + ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len ); + if ( ret < 0 ) { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt, + (long)len, strerror( errno ) ); + } + else { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt, + (long)len, (long)ret ); + ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + (const char *)buf, ret ); + } + return ret; +} + +static ber_slen_t +sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) +{ + ber_slen_t ret; + + ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); + if ( ret < 0 ) { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%swrite: want=%ld error=%s\n", + (char *)sbiod->sbiod_pvt, (long)len, + strerror( errno ) ); + } + else { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%swrite: want=%ld, written=%ld\n", + (char *)sbiod->sbiod_pvt, (long)len, (long)ret ); + ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + (const char *)buf, ret ); + } + return ret; +} + +Sockbuf_IO ber_sockbuf_io_debug = +{ + sb_debug_setup, /* sbi_setup */ + sb_debug_remove, /* sbi_remove */ + sb_debug_ctrl, /* sbi_ctrl */ + sb_debug_read, /* sbi_read */ + sb_debug_write, /* sbi_write */ + NULL /* sbi_close */ +}; + diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c index b2b24b2f58..3ce621f7aa 100644 --- a/libraries/libldap/abandon.c +++ b/libraries/libldap/abandon.c @@ -180,7 +180,7 @@ do_abandon( if ( lr != NULL ) { sb = lr->lr_conn->lconn_sb; } else { - sb = &ld->ld_sb; + sb = ld->ld_sb; } if ( ber_flush( sb, ber, 1 ) != 0 ) { diff --git a/libraries/libldap/cldap.c b/libraries/libldap/cldap.c index 0b03b2ad8d..9a4eac20ff 100644 --- a/libraries/libldap/cldap.c +++ b/libraries/libldap/cldap.c @@ -94,10 +94,20 @@ cldap_open( LDAP_CONST char *host, int port ) ld->ld_cldapnaddr = 0; ld->ld_cldapaddrs = NULL; - if (ber_pvt_sb_set_io( &(ld->ld_sb), &ber_pvt_sb_io_udp, NULL )<0) { + if ( ber_sockbuf_add_io( ld->ld_sb, &ber_sockbuf_io_udp, + LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ) < 0 ) { ldap_ld_free(ld, 1, NULL, NULL ); + tcp_close( s ); return NULL; } + if ( ber_sockbuf_add_io( ld->ld_sb, &ber_sockbuf_io_readahead, + LBER_SBIOD_LEVEL_PROVIDER, NULL ) < 0 ) { + ldap_ld_free( ld, 1, NULL, NULL ); + return NULL; + } +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( ld->ld_sb, &ber_sockbuf_io_debug, INT_MAX, NULL ); +#endif ld->ld_version = LDAP_VERSION2; @@ -168,7 +178,8 @@ cldap_open( LDAP_CONST char *host, int port ) DO_RETURN( NULL ); } - ber_pvt_sb_udp_set_dst( &ld->ld_sb, ld->ld_cldapaddrs[0] ); + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_SET_DST, + ld->ld_cldapaddrs[0] ); cldap_setretryinfo( ld, 0, 0 ); @@ -229,8 +240,8 @@ cldap_search_s( LDAP *ld, --ld->ld_msgid; /* use same id as before */ } - ber_pvt_sb_udp_set_dst( &(ld->ld_sb), - ld->ld_cldapaddrs[ cri.cri_useaddr ] ); + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_SET_DST, + (void *)ld->ld_cldapaddrs[cri.cri_useaddr] ); Debug( LDAP_DEBUG_TRACE, "cldap_search_s try %d (to %s)\n", cri.cri_try, inet_ntoa( ((struct sockaddr_in *) @@ -287,7 +298,6 @@ static int cldap_result( LDAP *ld, int msgid, LDAPMessage **res, struct cldap_retinfo *crip, const char *base ) { - Sockbuf *sb = &ld->ld_sb; BerElement ber; char *logdn; int ret, fromaddr, i; @@ -365,7 +375,7 @@ cldap_result( LDAP *ld, int msgid, LDAPMessage **res, * got a result: determine which server it came from * decode into ldap message chain */ - src = (struct sockaddr_in *) ber_pvt_sb_udp_get_src( sb ); + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_GET_SRC, (void *)&src ); for ( fromaddr = 0; fromaddr < ld->ld_cldapnaddr; ++fromaddr ) { if ( memcmp( &((struct sockaddr_in *) @@ -401,7 +411,8 @@ cldap_result( LDAP *ld, int msgid, LDAPMessage **res, if ( i == fromaddr ) { continue; } - ber_pvt_sb_udp_set_dst( sb, ld->ld_cldapaddrs[i] ); + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_SET_DST, + (void *)ld->ld_cldapaddrs[i] ); Debug( LDAP_DEBUG_TRACE, "cldap_result abandoning id %d (to %s)\n", msgid, inet_ntoa( ((struct sockaddr_in *) diff --git a/libraries/libldap/kbind.c b/libraries/libldap/kbind.c index 54982ae1a0..3f6f20cdd1 100644 --- a/libraries/libldap/kbind.c +++ b/libraries/libldap/kbind.c @@ -273,7 +273,7 @@ ldap_get_kerberosv4_credentials( return( NULL ); } - if( ! ber_pvt_sb_in_use( &ld->ld_sb ) ) { + if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected yet */ int rc = ldap_open_defconn( ld ); diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index df499916be..216a9b44e1 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -20,12 +20,13 @@ #include "../liblber/lber-int.h" #define ldap_debug (ldap_int_global_options.ldo_debug) + +#include "ldap_log.h" + #undef Debug #define Debug( level, fmt, arg1, arg2, arg3 ) \ ldap_log_printf( NULL, (level), (fmt), (arg1), (arg2), (arg3) ) -#include "ldap_log.h" - #include "ldap.h" #include "ldap_pvt.h" @@ -230,7 +231,7 @@ typedef struct ldapreqinfo { */ struct ldap { - Sockbuf ld_sb; /* socket descriptor & buffer */ + Sockbuf *ld_sb; /* socket descriptor & buffer */ struct ldapoptions ld_options; @@ -391,8 +392,6 @@ LIBLDAP_F (int) ldap_int_tblsize; LIBLDAP_F (int) ldap_int_timeval_dup( struct timeval **dest, const struct timeval *tm ); LIBLDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb, const char *host, unsigned long address, int port, int async ); -LIBLDAP_F (void) ldap_close_connection( Sockbuf *sb ); - #if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) LIBLDAP_F (char *) ldap_host_connected_to( Sockbuf *sb ); #endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND */ diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c index 955733482f..afccb261d7 100644 --- a/libraries/libldap/open.c +++ b/libraries/libldap/open.c @@ -161,7 +161,13 @@ ldap_create( LDAP **ldp ) #endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */ #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */ - ber_pvt_sb_init( &(ld->ld_sb) ); + ld->ld_sb = ber_sockbuf_alloc( ); + if ( ld->ld_sb == NULL ) { + ldap_free_urllist( ld->ld_options.ldo_defludp ); + LDAP_FREE( (char*) ld ); + WSACleanup( ); + return LDAP_NO_MEMORY; + } *ldp = ld; return LDAP_SUCCESS; @@ -283,24 +289,41 @@ open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, switch ( srv->lud_protocol ) { case LDAP_PROTO_TCP: + rc = ldap_connect_to_host( ld, sb, srv->lud_host, + addr, port, async ); + if ( rc == -1 ) + return rc; + ber_sockbuf_add_io( sb, &ber_sockbuf_io_tcp, + LBER_SBIOD_LEVEL_PROVIDER, NULL ); + break; case LDAP_PROTO_UDP: - rc = ldap_connect_to_host( ld, sb, srv->lud_host, addr, port, async ); + rc = ldap_connect_to_host( ld, sb, srv->lud_host, + addr, port, async ); + if ( rc == -1 ) + return rc; + ber_sockbuf_add_io( sb, &ber_sockbuf_io_udp, + LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #ifdef LDAP_PF_LOCAL case LDAP_PROTO_LOCAL: - rc = ldap_connect_to_path( ld, sb, srv->lud_host, async ); + rc = ldap_connect_to_path( ld, sb, srv->lud_host, + async ); + if ( rc == -1 ) + return rc; + ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, + LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #endif /* LDAP_PF_LOCAL */ default: - rc = -1; + return -1; break; } - if ( rc == -1 ) { - return( rc ); - } - - ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); + ber_sockbuf_add_io( sb, &ber_sockbuf_io_readahead, + LBER_SBIOD_LEVEL_PROVIDER, NULL ); +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, INT_MAX, NULL ); +#endif #ifdef HAVE_TLS if (ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD || diff --git a/libraries/libldap/options.c b/libraries/libldap/options.c index 47e77e6247..56b39c20f4 100644 --- a/libraries/libldap/options.c +++ b/libraries/libldap/options.c @@ -151,12 +151,12 @@ ldap_get_option( } break; case LDAP_OPT_DESC: - if(ld == NULL) { + if( ld == NULL || ld->ld_sb == NULL ) { /* bad param */ break; } - * (ber_socket_t *) outvalue = ber_pvt_sb_get_desc( &(ld->ld_sb) ); + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue ); return LDAP_OPT_SUCCESS; case LDAP_OPT_TIMEOUT: diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c index 1033d62c52..f150eb4ff6 100644 --- a/libraries/libldap/os-ip.c +++ b/libraries/libldap/os-ip.c @@ -337,7 +337,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb, const char *host, rc = ldap_pvt_connect(ld, s, &sin, async); if ( (rc == 0) || (rc == -2) ) { - ber_pvt_sb_set_desc( sb, s ); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s ); break; } @@ -350,13 +350,6 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb, const char *host, return rc; } -void -ldap_close_connection( Sockbuf *sb ) -{ - ber_pvt_sb_close( sb ); -} - - #if defined( LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND ) || defined( HAVE_TLS ) || defined( HAVE_CYRUS_SASL ) char * ldap_host_connected_to( Sockbuf *sb ) @@ -369,12 +362,14 @@ ldap_host_connected_to( Sockbuf *sb ) struct hostent he_buf; int local_h_errno; char *ha_buf=NULL; + ber_socket_t sd; #define DO_RETURN(x) if (ha_buf) LDAP_FREE(ha_buf); return (x); (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in )); len = sizeof( sin ); - if ( getpeername( ber_pvt_sb_get_desc(sb), (struct sockaddr *)&sin, &len ) == -1 ) { + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); + if ( getpeername( sd, (struct sockaddr *)&sin, &len ) == -1 ) { return( NULL ); } @@ -414,11 +409,13 @@ void ldap_mark_select_write( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; + ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; - if ( !FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_writefds )) { - FD_SET( (u_int) sb->sb_sd, &sip->si_writefds ); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); + if ( !FD_ISSET( sd, &sip->si_writefds )) { + FD_SET( sd, &sip->si_writefds ); } } @@ -427,11 +424,13 @@ void ldap_mark_select_read( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; + ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; - if ( !FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_readfds )) { - FD_SET( (u_int) sb->sb_sd, &sip->si_readfds ); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); + if ( !FD_ISSET( sd, &sip->si_readfds )) { + FD_SET( sd, &sip->si_readfds ); } } @@ -440,11 +439,13 @@ void ldap_mark_select_clear( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; + ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; - FD_CLR( (u_int) ber_pvt_sb_get_desc(sb), &sip->si_writefds ); - FD_CLR( (u_int) ber_pvt_sb_get_desc(sb), &sip->si_readfds ); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); + FD_CLR( sd, &sip->si_writefds ); + FD_CLR( sd, &sip->si_readfds ); } @@ -452,10 +453,12 @@ int ldap_is_write_ready( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; + ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; - return( FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_use_writefds )); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); + return( FD_ISSET( sd, &sip->si_use_writefds )); } @@ -463,10 +466,12 @@ int ldap_is_read_ready( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; + ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; - return( FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_use_readfds )); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); + return( FD_ISSET( sd, &sip->si_use_readfds )); } diff --git a/libraries/libldap/os-local.c b/libraries/libldap/os-local.c index baae3da352..67da7e0328 100644 --- a/libraries/libldap/os-local.c +++ b/libraries/libldap/os-local.c @@ -208,7 +208,7 @@ ldap_connect_to_path(LDAP *ld, Sockbuf *sb, const char *path, int async) rc = ldap_pvt_connect(ld, s, &server, async); if (rc == 0) { - ber_pvt_sb_set_desc( sb, s ); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, (void *)&s ); } else { ldap_pvt_close_socket(ld, s); } diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index 87d6c84bfa..bb6c9df78d 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -100,7 +100,7 @@ ldap_send_initial_request( Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 ); - if ( ! ber_pvt_sb_in_use(&ld->ld_sb ) ) { + if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected yet */ int rc = ldap_open_defconn( ld ); @@ -293,7 +293,7 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb, return( NULL ); } - lc->lconn_sb = ( use_ldsb ) ? &ld->ld_sb : sb; + lc->lconn_sb = ( use_ldsb ) ? ld->ld_sb : sb; if ( connect ) { for ( srv = srvlist; srv != NULL; srv = srv->lud_next ) { @@ -433,10 +433,6 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) } } - /* force closure */ - ldap_close_connection( lc->lconn_sb ); - ber_pvt_sb_destroy( lc->lconn_sb ); - if( lc->lconn_ber != NULL ) { ber_free( lc->lconn_ber, 1 ); } @@ -458,7 +454,7 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) if ( lc->lconn_krbinstance != NULL ) { LDAP_FREE( lc->lconn_krbinstance ); } - if ( lc->lconn_sb != &ld->ld_sb ) { + if ( lc->lconn_sb != ld->ld_sb ) { ber_sockbuf_free( lc->lconn_sb ); } if( lc->lconn_rebind_queue != NULL) { @@ -493,7 +489,7 @@ ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ) ( lc->lconn_server->lud_host == NULL ) ? "(null)" : lc->lconn_server->lud_host, lc->lconn_server->lud_port, ( lc->lconn_sb == - &ld->ld_sb ) ? " (default)" : "" ); + ld->ld_sb ) ? " (default)" : "" ); } fprintf( stderr, " refcnt: %d status: %s\n", lc->lconn_refcnt, ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ? diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 3ceb1fa70d..475effc9d5 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -218,7 +218,8 @@ wait4msg( } #endif /* LDAP_DEBUG */ for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { - if ( ber_pvt_sb_data_ready(lc->lconn_sb) ) { + if ( ber_sockbuf_ctrl( lc->lconn_sb, + LBER_SB_OPT_DATA_READY, NULL ) ) { rc = try_read1msg( ld, msgid, all, lc->lconn_sb, lc, result ); break; @@ -888,14 +889,16 @@ cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber ) int rc; ber_tag_t tag; ber_len_t len; + ber_socket_t sd; - if ( ! ber_pvt_sb_data_ready(&ld->ld_sb) ) { + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ); + if ( sd != AC_SOCKET_INVALID ) { /* restored from ldap_select1() in result.c version 1.24 */ fd_set readfds; if ( ldap_int_tblsize == 0 ) ldap_int_ip_init(); FD_ZERO( &readfds ); - FD_SET( ber_pvt_sb_get_desc(&ld->ld_sb), &readfds ); + FD_SET( sd, &readfds ); rc = select( ldap_int_tblsize, &readfds, 0, 0, timeout ); if ( rc == -1 || rc == 0 ) { @@ -906,7 +909,7 @@ cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber ) } /* get the next message */ - if ( (tag = ber_get_next( &ld->ld_sb, &len, ber )) + if ( (tag = ber_get_next( ld->ld_sb, &len, ber )) != LDAP_TAG_MESSAGE ) { ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN : LDAP_LOCAL_ERROR); diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c index 00656001d9..e162b04a53 100644 --- a/libraries/libldap/sasl.c +++ b/libraries/libldap/sasl.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "ldap-int.h" @@ -349,22 +350,8 @@ ldap_parse_sasl_bind_result( * Various Cyrus SASL related stuff. */ -static int sasl_setup( Sockbuf *sb, void *arg ); -static int sasl_remove( Sockbuf *sb ); -static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len ); -static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len ); -static int sasl_close( Sockbuf *sb ); - -static Sockbuf_IO sasl_io= -{ -sasl_setup, -sasl_remove, -sasl_read, -sasl_write, -sasl_close -}; - -#define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io) +#define MAX_BUFF_SIZE 65536 +#define MIN_BUFF_SIZE 4096 static char * array2str( char **a ) @@ -424,79 +411,259 @@ int ldap_pvt_sasl_init( void ) return -1; } -int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg ) +/* + * SASL encryption support for LBER Sockbufs + */ + +struct sb_sasl_data { + sasl_conn_t *sasl_context; + Sockbuf_Buf sec_buf_in; + Sockbuf_Buf buf_in; + Sockbuf_Buf buf_out; +}; + +static int +sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { - /* don't install the stuff unless security has been negotiated */ + struct sb_sasl_data *p; - if ( !HAS_SASL( sb ) ) { - ber_pvt_sb_clear_io( sb ); - ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg ); + assert( sbiod != NULL ); + + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) + return -1; + p->sasl_context = (sasl_conn_t *)arg; + ber_pvt_sb_buf_init( &p->sec_buf_in ); + ber_pvt_sb_buf_init( &p->buf_in ); + ber_pvt_sb_buf_init( &p->buf_out ); + if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, MIN_BUFF_SIZE ) < 0 ) { + errno = ENOMEM; + return -1; } + sbiod->sbiod_pvt = p; + return 0; } -static int sasl_setup( Sockbuf *sb, void *arg ) +static int +sb_sasl_remove( Sockbuf_IO_Desc *sbiod ) { - sb->sb_iodata = arg; + struct sb_sasl_data *p; + + assert( sbiod != NULL ); + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; + ber_pvt_sb_buf_destroy( &p->sec_buf_in ); + ber_pvt_sb_buf_destroy( &p->buf_in ); + ber_pvt_sb_buf_destroy( &p->buf_out ); + LBER_FREE( p ); + sbiod->sbiod_pvt = NULL; return 0; } -static int sasl_remove( Sockbuf *sb ) +static ber_len_t +sb_sasl_pkt_length( const char *buf, int debuglevel ) { - return 0; + ber_len_t size; + long tmp; + + assert( buf != NULL ); + + tmp = *((long *)buf); + size = ntohl( tmp ); + + if ( size > MAX_BUFF_SIZE ) { + /* somebody is trying to mess me up. */ + ber_log_printf( LDAP_DEBUG_ANY, debuglevel, + "sb_sasl_pkt_length: received illegal packet length " + "of %lu bytes\n", (unsigned long)size ); + size = 16; /* this should lead to an error. */ +} + + return size + 4; /* include the size !!! */ } -static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen ) +/* Drop a processed packet from the input buffer */ +static void +sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel ) { - char *recv_tok; - unsigned recv_tok_len; - sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata; + ber_slen_t len; + + len = sec_buf_in->buf_ptr - sec_buf_in->buf_end; + if ( len > 0 ) + memmove( sec_buf_in->buf_base, sec_buf_in->buf_base + + sec_buf_in->buf_end, len ); + + if ( len >= 4 ) { + sec_buf_in->buf_end = sb_sasl_pkt_length( sec_buf_in->buf_base, + debuglevel); + } + else { + sec_buf_in->buf_end = 0; + } + sec_buf_in->buf_ptr = len; +} - if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) { - return -1; +static ber_slen_t +sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct sb_sasl_data *p; + ber_slen_t ret, bufptr; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; + + /* Are there anything left in the buffer? */ + ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len ); + bufptr = ret; + len -= ret; + + if ( len == 0 ) + return bufptr; + + ber_pvt_sb_buf_destroy( &p->buf_in ); + + /* Read the length of the packet */ + while ( p->sec_buf_in.buf_ptr < 4 ) { + ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base, + 4 - p->sec_buf_in.buf_ptr ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) + continue; +#endif + if ( ret <= 0 ) + return ret; + + p->sec_buf_in.buf_ptr += ret; } - if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) { + /* The new packet always starts at p->sec_buf_in.buf_base */ + ret = sb_sasl_pkt_length( p->sec_buf_in.buf_base, + sbiod->sbiod_sb->sb_debug ); + + /* Grow the packet buffer if neccessary */ + if ( ( p->sec_buf_in.buf_size < ret ) && + ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 ) { + errno = ENOMEM; return -1; } - - if ( recv_tok_len > buflen ) { - LDAP_FREE( recv_tok ); + p->sec_buf_in.buf_end = ret; + + /* Did we read the whole encrypted packet? */ + while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) { + /* No, we have got only a part of it */ + ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr; + + ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base + + p->sec_buf_in.buf_ptr, ret ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) + continue; +#endif + if ( ret <= 0 ) + return ret; + + p->sec_buf_in.buf_ptr += ret; + } + + /* Decode the packet */ + ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base, + p->sec_buf_in.buf_end, &p->buf_in.buf_base, + (unsigned *)&p->buf_in.buf_end ); + if ( ret != SASL_OK ) { + ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, + "sb_sasl_read: failed to decode packet: %s\n", + sasl_errstring( ret, NULL, NULL ) ); + sb_sasl_drop_packet( &p->sec_buf_in, + sbiod->sbiod_sb->sb_debug ); + errno = EIO; return -1; } + + /* Drop the packet from the input buffer */ + sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug ); - memcpy( buf, recv_tok, recv_tok_len ); + p->buf_in.buf_size = p->buf_in.buf_end; - LDAP_FREE( recv_tok ); + bufptr += ber_pvt_sb_copy_out( &p->buf_in, buf + bufptr, len ); - return recv_tok_len; + return bufptr; } -static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len ) +static ber_slen_t +sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { - char *wrapped_tok; - unsigned wrapped_tok_len; - sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata; + struct sb_sasl_data *p; + int ret; - if ( sasl_encode( conn, (const char *)buf, len, - &wrapped_tok, &wrapped_tok_len ) != SASL_OK ) { - return -1; + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; + + /* Are there anything left in the buffer? */ + if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { + ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); + if ( ret <= 0 ) + return ret; } - if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) { - LDAP_FREE( wrapped_tok ); + /* now encode the next packet. */ + ber_pvt_sb_buf_destroy( &p->buf_out ); + ret = sasl_encode( p->sasl_context, buf, len, &p->buf_out.buf_base, + (unsigned *)&p->buf_out.buf_size ); + if ( ret != SASL_OK ) { + ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, + "sb_sasl_write: failed to encode packet: %s\n", + sasl_errstring( ret, NULL, NULL ) ); return -1; } + p->buf_out.buf_end = p->buf_out.buf_size; - LDAP_FREE( wrapped_tok ); - + ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); + if ( ret <= 0 ) + return ret; return len; } -static int sasl_close( Sockbuf *sb ) +static int +sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { - return (ber_pvt_sb_io_tcp.sbi_close)( sb ); + struct sb_sasl_data *p; + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_DATA_READY ) { + if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) + return 1; + } + + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +Sockbuf_IO ldap_pvt_sockbuf_io_sasl = +{ + sb_sasl_setup, /* sbi_setup */ + sb_sasl_remove, /* sbi_remove */ + sb_sasl_ctrl, /* sbi_ctrl */ + sb_sasl_read, /* sbi_read */ + sb_sasl_write, /* sbi_write */ + NULL /* sbi_close */ +}; + +int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg ) +{ + /* don't install the stuff unless security has been negotiated */ + + if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, + &ldap_pvt_sockbuf_io_sasl ) ) + ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl, + LBER_SBIOD_LEVEL_APPLICATION, ctx_arg ); + + return LDAP_SUCCESS; } static int @@ -598,11 +765,16 @@ ldap_pvt_sasl_bind( LDAPControl **cctrls ) { const char *mech; - int saslrc, rc, ssf = 0; + int saslrc, rc; + sasl_ssf_t *ssf = NULL; unsigned credlen; struct berval ccred, *scred; char *host; sasl_interact_t *client_interact = NULL; + struct sockaddr_in sin; + socklen_t len; + sasl_security_properties_t secprops; + ber_socket_t sd; Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 ); @@ -612,15 +784,18 @@ ldap_pvt_sasl_bind( return ld->ld_errno; } - if( ! ber_pvt_sb_in_use( &ld->ld_sb ) ) { + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ); + + if ( sd == AC_SOCKET_INVALID ) { /* not connected yet */ int rc = ldap_open_defconn( ld ); if( rc < 0 ) return ld->ld_errno; + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ); } /* XXX this doesn't work with PF_LOCAL hosts */ - host = ldap_host_connected_to( &ld->ld_sb ); + host = ldap_host_connected_to( ld->ld_sb ); if ( host == NULL ) { ld->ld_errno = LDAP_UNAVAILABLE; @@ -631,16 +806,42 @@ ldap_pvt_sasl_bind( sasl_dispose( &ld->ld_sasl_context ); } - saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context ); + saslrc = sasl_client_new( "ldap", host, callbacks, SASL_SECURITY_LAYER, + &ld->ld_sasl_context ); LDAP_FREE( host ); if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { - ld->ld_errno = sasl_err2ldap( rc ); + ld->ld_errno = sasl_err2ldap( saslrc ); sasl_dispose( &ld->ld_sasl_context ); return ld->ld_errno; } + len = sizeof( sin ); + if ( getpeername( sd, (struct sockaddr *)&sin, &len ) == -1 ) { + Debug( LDAP_DEBUG_ANY, "SASL: can't query remote IP.\n", + 0, 0, 0 ); + ld->ld_errno = LDAP_OPERATIONS_ERROR; + return ld->ld_errno; + } + sasl_setprop( ld->ld_sasl_context, SASL_IP_REMOTE, &sin ); + + len = sizeof( sin ); + if ( getsockname( sd, (struct sockaddr *)&sin, &len ) == -1 ) { + Debug( LDAP_DEBUG_ANY, "SASL: can't query local IP.\n", + 0, 0, 0 ); + ld->ld_errno = LDAP_OPERATIONS_ERROR; + return ld->ld_errno; + } + sasl_setprop( ld->ld_sasl_context, SASL_IP_LOCAL, &sin ); + + memset( &secprops, 0, sizeof( secprops ) ); + secprops.min_ssf = ld->ld_options.ldo_sasl_minssf; + secprops.max_ssf = ld->ld_options.ldo_sasl_maxssf; + secprops.security_flags = SASL_SECURITY_LAYER; + secprops.maxbufsize = 65536; + sasl_setprop( ld->ld_sasl_context, SASL_SEC_PROPS, &secprops ); + ccred.bv_val = NULL; ccred.bv_len = 0; @@ -702,8 +903,8 @@ ldap_pvt_sasl_bind( assert ( rc == LDAP_SUCCESS ); if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf ) - == SASL_OK && ssf ) { - ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context ); + == SASL_OK && ssf && *ssf ) { + ldap_pvt_sasl_install( ld->ld_sb, ld->ld_sasl_context ); } return rc; diff --git a/libraries/libldap/test.c b/libraries/libldap/test.c index f32fe6954b..cdcadc9fb2 100644 --- a/libraries/libldap/test.c +++ b/libraries/libldap/test.c @@ -235,6 +235,9 @@ bind_prompt( LDAP *ld, LDAP_CONST char *url, int request, ber_int_t msgid) char *dnp; int authmethod; + printf("rebind for request=%d msgid=%ld url=%s\n", + request, (long) msgid, url ); + #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND getline( dn, sizeof(dn), stdin, "re-bind method (0->simple, 1->krbv41, 2->krbv42, 3->krbv41&2)? " ); @@ -321,12 +324,12 @@ main( int argc, char **argv ) case 't': /* copy ber's to given file */ copyfname = strdup( optarg ); - copyoptions = LBER_TO_FILE; +/* copyoptions = LBER_TO_FILE; */ break; case 'T': /* only output ber's to given file */ copyfname = strdup( optarg ); - copyoptions = (LBER_TO_FILE | LBER_TO_FILE_ONLY); +/* copyoptions = (LBER_TO_FILE | LBER_TO_FILE_ONLY); */ break; default: @@ -362,12 +365,12 @@ main( int argc, char **argv ) } if ( copyfname != NULL ) { - if ( (ld->ld_sb.sb_fd = open( copyfname, O_WRONLY | O_CREAT, + if ( ( ld->ld_sb->sb_fd = open( copyfname, O_WRONLY | O_CREAT, 0600 )) == -1 ) { perror( copyfname ); exit ( EXIT_FAILURE ); } - ld->ld_sb.sb_options = copyoptions; + ld->ld_sb->sb_options = copyoptions; } bound = 0; diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index 32a773cfca..ff72666090 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -41,24 +41,11 @@ static char *tls_opt_cacertdir = NULL; static int tls_opt_require_cert = 0; static char *tls_opt_ciphersuite = NULL; -#define HAS_TLS( sb ) ((sb)->sb_io==&tls_io) +#define HAS_TLS( sb ) ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \ + (void *)&ldap_pvt_sockbuf_io_tls ) -static int tls_setup( Sockbuf *sb, void *arg ); -static int tls_remove( Sockbuf *sb ); -static ber_slen_t tls_read( Sockbuf *sb, void *buf, ber_len_t len ); -static ber_slen_t tls_write( Sockbuf *sb, void *buf, ber_len_t len ); -static int tls_close( Sockbuf *sb ); static void tls_report_error( void ); -static Sockbuf_IO tls_io= -{ - tls_setup, - tls_remove, - tls_read, - tls_write, - tls_close -}; - static void tls_info_cb( SSL *ssl, int where, int ret ); static int tls_verify_cb( int ok, X509_STORE_CTX *ctx ); static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); @@ -243,9 +230,8 @@ get_ca_list( char * bundle, char * dir ) } static SSL * -alloc_handle( Sockbuf *sb, void *ctx_arg ) +alloc_handle( void *ctx_arg ) { - int err; SSL_CTX *ctx; SSL *ssl; @@ -266,8 +252,6 @@ alloc_handle( Sockbuf *sb, void *ctx_arg ) if ( tls_opt_trace ) { SSL_set_info_callback( ssl, tls_info_cb ); } - sb->sb_iodata = ssl; - SSL_set_fd( ssl, ber_pvt_sb_get_desc( sb ) ); return ssl; } @@ -293,6 +277,252 @@ update_flags( Sockbuf *sb, SSL * ssl, int rc ) return 0; } +/* + * TLS support for LBER Sockbufs + */ + +struct tls_data { + SSL *ssl; + Sockbuf_IO_Desc *sbiod; +}; + +extern BIO_METHOD ldap_pvt_sb_bio_method; + +static int +sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg ) +{ + struct tls_data *p; + BIO *bio; + + assert( sbiod != NULL ); + + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) + return -1; + + p->ssl = (SSL *)arg; + p->sbiod = sbiod; + bio = BIO_new( &ldap_pvt_sb_bio_method ); + bio->ptr = (void *)p; + SSL_set_bio( p->ssl, bio, bio ); + sbiod->sbiod_pvt = p; + return 0; +} + +static int +sb_tls_remove( Sockbuf_IO_Desc *sbiod ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + SSL_free( p->ssl ); + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; + return 0; +} + +static int +sb_tls_close( Sockbuf_IO_Desc *sbiod ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + SSL_shutdown( p->ssl ); + return 0; +} + +static int +sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_GET_SSL ) { + *((SSL **)arg) = p->ssl; + return 1; + } + + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +static ber_slen_t +sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct tls_data *p; + ber_slen_t ret; + int err; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + ret = SSL_read( p->ssl, (char *)buf, len ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + err = SSL_get_error( p->ssl, ret ); + if (err == SSL_ERROR_WANT_READ ) { + sbiod->sbiod_sb->sb_trans_needs_read = 1; +#ifdef WIN32 + errno = EWOULDBLOCK; +#endif + } + else + sbiod->sbiod_sb->sb_trans_needs_read = 0; + return ret; +} + +static ber_slen_t +sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct tls_data *p; + ber_slen_t ret; + int err; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + ret = SSL_write( p->ssl, (char *)buf, len ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + err = SSL_get_error( p->ssl, ret ); + if (err == SSL_ERROR_WANT_WRITE ) { + sbiod->sbiod_sb->sb_trans_needs_write = 1; +#ifdef WIN32 + errno = EWOULDBLOCK; +#endif + } + else + sbiod->sbiod_sb->sb_trans_needs_write = 0; + return ret; +} + +Sockbuf_IO ldap_pvt_sockbuf_io_tls = +{ + sb_tls_setup, /* sbi_setup */ + sb_tls_remove, /* sbi_remove */ + sb_tls_ctrl, /* sbi_ctrl */ + sb_tls_read, /* sbi_read */ + sb_tls_write, /* sbi_write */ + sb_tls_close /* sbi_close */ +}; + +static int +sb_tls_bio_create( BIO *b ) { + b->init = 1; + b->num = 0; + b->ptr = NULL; + b->flags = 0; + return 1; +} + +static int +sb_tls_bio_destroy( BIO *b ) +{ + if ( b == NULL ) + return 0; + + b->ptr = NULL; /* sb_tls_remove() will free it */ + b->init = 0; + b->flags = 0; + return 1; +} + +static int +sb_tls_bio_read( BIO *b, char *buf, int len ) +{ + struct tls_data *p; + int ret; + + if ( buf == NULL || len <= 0 ) + return 0; + + p = (struct tls_data *)b->ptr; + + if ( p == NULL || p->sbiod == NULL ) + return 0; + + ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len ); + + BIO_clear_retry_flags( b ); + if ( ret < 0 && errno == EWOULDBLOCK ) + BIO_set_retry_read( b ); + + return ret; +} + +static int +sb_tls_bio_write( BIO *b, char *buf, int len ) +{ + struct tls_data *p; + int ret; + + if ( buf == NULL || len <= 0 ) + return 0; + + p = (struct tls_data *)b->ptr; + + if ( p == NULL || p->sbiod == NULL ) + return 0; + + ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, buf, len ); + + BIO_clear_retry_flags( b ); + if ( ret < 0 && errno == EWOULDBLOCK ) + BIO_set_retry_write( b ); + + return ret; +} + +static long +sb_tls_bio_ctrl( BIO *b, int cmd, long num, char *ptr ) +{ + if ( cmd == BIO_CTRL_FLUSH ) { + /* The OpenSSL library needs this */ + return 1; + } + return 0; +} + +static int +sb_tls_bio_gets( BIO *b, char *buf, int len ) +{ + return -1; +} + +static int +sb_tls_bio_puts( BIO *b, char *str ) +{ + return sb_tls_bio_write( b, str, strlen( str ) ); +} + +BIO_METHOD ldap_pvt_sb_bio_method = +{ + ( 100 | 0x400 ), /* it's a source/sink BIO */ + "sockbuf glue", + sb_tls_bio_write, + sb_tls_bio_read, + sb_tls_bio_puts, + sb_tls_bio_gets, + sb_tls_bio_ctrl, + sb_tls_bio_create, + sb_tls_bio_destroy +}; + /* * Call this to do a TLS connect on a sockbuf. ctx_arg can be * a SSL_CTX * or NULL, in which case the default ctx is used. @@ -313,13 +543,17 @@ ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, void *ctx_arg ) SSL *ssl; if ( HAS_TLS( sb ) ) { - ssl = (SSL *) sb->sb_iodata; + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); } else { - ssl = alloc_handle( sb, ctx_arg ); + ssl = alloc_handle( ctx_arg ); if ( ssl == NULL ) return -1; - ber_pvt_sb_clear_io( sb ); - ber_pvt_sb_set_io( sb, &tls_io, (void *)ssl ); +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" ); +#endif + ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_tls, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); } err = SSL_connect( ssl ); @@ -335,8 +569,12 @@ ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, void *ctx_arg ) ld->ld_error = ldap_strdup(ERR_error_string(err, buf)); } Debug( LDAP_DEBUG_ANY,"TLS: can't connect.\n",0,0,0); - ber_pvt_sb_clear_io( sb ); - ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); + ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_tls, + LBER_SBIOD_LEVEL_TRANSPORT ); +#ifdef LDAP_DEBUG + ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT ); +#endif return -1; } return 0; @@ -353,13 +591,17 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) SSL *ssl; if ( HAS_TLS( sb ) ) { - ssl = (SSL *) sb->sb_iodata; + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); } else { - ssl = alloc_handle( sb, ctx_arg ); + ssl = alloc_handle( ctx_arg ); if ( ssl == NULL ) return -1; - ber_pvt_sb_clear_io( sb ); - ber_pvt_sb_set_io( sb, &tls_io, (void *)ssl ); +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" ); +#endif + ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_tls, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); } err = SSL_accept( ssl ); @@ -372,8 +614,12 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) return 1; Debug( LDAP_DEBUG_ANY,"TLS: can't accept.\n",0,0,0 ); tls_report_error(); - ber_pvt_sb_clear_io( sb ); - ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); + ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_tls, + LBER_SBIOD_LEVEL_TRANSPORT ); +#ifdef LDAP_DEBUG + ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT ); +#endif return -1; } return 0; @@ -390,16 +636,19 @@ ldap_pvt_tls_inplace ( Sockbuf *sb ) void * ldap_pvt_tls_sb_handle( Sockbuf *sb ) { - if (HAS_TLS( sb )) - return sb->sb_iodata; - else + void *p; + + if (HAS_TLS( sb )) { + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p ); + return p; + } return NULL; } void * ldap_pvt_tls_get_handle( LDAP *ld ) { - return ldap_pvt_tls_sb_handle(&ld->ld_sb); + return ldap_pvt_tls_sb_handle( ld->ld_sb ); } const char * @@ -568,60 +817,6 @@ ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg ) return LDAP_SUCCESS; } - -static int -tls_setup( Sockbuf *sb, void *arg ) -{ - sb->sb_iodata = arg; - return 0; -} - -static int -tls_remove( Sockbuf *sb ) -{ - SSL_free( (SSL *) sb->sb_iodata ); - return 0; -} - -static ber_slen_t -tls_write( Sockbuf *sb, void *buf, ber_len_t sz ) -{ - int ret = SSL_write( (SSL *)sb->sb_iodata, buf, sz ); - -#ifdef HAVE_WINSOCK - errno = WSAGetLastError(); -#endif - update_flags(sb, (SSL *)sb->sb_iodata, ret ); -#ifdef WIN32 - if (sb->sb_trans_needs_write) - errno = EWOULDBLOCK; -#endif - return ret; -} - -static ber_slen_t -tls_read( Sockbuf *sb, void *buf, ber_len_t sz ) -{ - int ret = SSL_read( (SSL *)sb->sb_iodata, buf, sz ); - -#ifdef HAVE_WINSOCK - errno = WSAGetLastError(); -#endif - update_flags(sb, (SSL *)sb->sb_iodata, ret ); -#ifdef WIN32 - if (sb->sb_trans_needs_read) - errno = EWOULDBLOCK; -#endif - return ret; -} - -static int -tls_close( Sockbuf *sb ) -{ - tcp_close( ber_pvt_sb_get_desc( sb ) ); - return 0; -} - /* Derived from openssl/apps/s_cb.c */ static void tls_info_cb( SSL *ssl, int where, int ret ) diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c index e858d6e343..7fd116f760 100644 --- a/libraries/libldap/unbind.c +++ b/libraries/libldap/unbind.c @@ -145,7 +145,7 @@ ldap_ld_free( } #endif - ber_pvt_sb_destroy( &(ld->ld_sb) ); + ber_sockbuf_free( ld->ld_sb ); LDAP_FREE( (char *) ld ); diff --git a/servers/ldapd/main.c b/servers/ldapd/main.c index 7e86443755..8d1d2659c4 100644 --- a/servers/ldapd/main.c +++ b/servers/ldapd/main.c @@ -38,7 +38,6 @@ #include #include "lber.h" -#include "../../libraries/liblber/lber-int.h" /* get struct sockbuf */ #include "ldap.h" #include "common.h" #include "lutil.h" /* Get lutil_detach() */ @@ -492,7 +491,7 @@ do_queries( fd_set readfds; int rc; struct timeval timeout; - Sockbuf sb; + Sockbuf *sb; #ifdef LDAP_CONNECTIONLESS struct sockaddr saddr, faddr; struct sockaddr *saddrlist[ 1 ]; @@ -515,10 +514,9 @@ do_queries( conn_init(); } - ber_pvt_sb_init( &sb ); - ber_pvt_sb_set_desc( &sb, clientsock ); - ber_pvt_sb_set_io( &sb, (udp) ? &ber_pvt_sb_io_udp : - &ber_pvt_sb_io_tcp, NULL ); + sb = ber_sockbuf_alloc( ); + ber_sockbuf_add_io( sb, (udp) ? &ber_sockbuf_io_udp : + &ber_sockbuf_io_tcp, (void *)&clientsock ); timeout.tv_sec = idletime; timeout.tv_usec = 0; for ( ;; ) { @@ -547,7 +545,7 @@ do_queries( * already waiting for us on the client sock. */ - if ( ! ber_pvt_sb_data_ready( &sb ) ) { + if ( ! ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) ) { if ( (rc = select( dtblsize, &readfds, 0, 0, udp ? 0 : &timeout )) < 1 ) { #ifdef LDAP_DEBUG @@ -573,9 +571,9 @@ do_queries( } } - if ( ber_pvt_sb_data_ready( &sb ) || + if ( ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) || FD_ISSET( clientsock, &readfds ) ) { - client_request( &sb, conns, udp ); + client_request( sb, conns, udp ); } else { if ( (dsaconn = conn_getfd( &readfds )) == NULL ) { Debug( LDAP_DEBUG_ANY, "No DSA activity!\n", @@ -583,7 +581,7 @@ do_queries( continue; } - dsa_response( dsaconn, &sb ); + dsa_response( dsaconn, sb ); } } /* NOT REACHED */ diff --git a/servers/ldapd/request.c b/servers/ldapd/request.c index 95598ff28a..8f27d30430 100644 --- a/servers/ldapd/request.c +++ b/servers/ldapd/request.c @@ -28,7 +28,6 @@ #include #include "lber.h" -#include "../../libraries/liblber/lber-int.h" /* get struct berelement */ #include "ldap.h" #include "common.h" @@ -89,7 +88,8 @@ client_request( #ifdef LDAP_CONNECTIONLESS if ( udp && dosyslog ) { - sai = (struct sockaddr_in *)ber_pvt_sb_udp_get_src( &clientsb ); + ber_sockbuf_ctrl( clientsb, LBER_SB_OPT_UDP_GET_SRC, + (void *)&sai ); syslog( LOG_INFO, "UDP request from unknown (%s)", inet_ntoa( sai->sin_addr ) ); } @@ -193,7 +193,7 @@ client_request( free( ber.ber_buf ); return; } - sai = (struct sockaddr_in *) ber_pvt_sb_udp_get_src( &clientsb ); + ber_sockbuf_ctrl( clientsb, LBER_SB_OPT_UDP_GET_SRC, (void *)&sai ); if ( get_cldap_msg( msgid, tag, (struct sockaddr *)sai ) != NULL ) { diff --git a/servers/ldapd/result.c b/servers/ldapd/result.c index 29ebd3e1bb..d7a8e1445a 100644 --- a/servers/ldapd/result.c +++ b/servers/ldapd/result.c @@ -24,7 +24,6 @@ #include #include "lber.h" -#include "../../libraries/liblber/lber-int.h" /* get struct berelement */ #include "ldap.h" #include "common.h" @@ -281,7 +280,8 @@ send_ldap_msgresult( { #ifdef LDAP_CONNECTIONLESS if ( m->m_cldap ) { - ber_pvt_sb_udp_set_dst( &sb, &m->m_clientaddr ); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_UDP_SET_DST, + (void *)&m->m_clientaddr ); Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", inet_ntoa(((struct sockaddr_in *) @@ -306,7 +306,7 @@ send_ldap_result( int rc; #ifdef LDAP_CONNECTIONLESS int cldap; - cldap = ( sb->sb_io == &ber_pvt_sb_io_udp ); + cldap = ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, &ber_sockbuf_io_udp ); #endif Debug( LDAP_DEBUG_TRACE, "send_ldap_result\n", 0, 0, 0 ); diff --git a/servers/ldapd/search.c b/servers/ldapd/search.c index 4ad1a3de8c..8ff3c194f6 100644 --- a/servers/ldapd/search.c +++ b/servers/ldapd/search.c @@ -26,7 +26,6 @@ #include #include "lber.h" -#include "../../libraries/liblber/lber-int.h" /* get struct berelement */ #include "ldap.h" #include "common.h" @@ -701,7 +700,8 @@ search_result( LDAP_OPERATIONS_ERROR, NULL, "ber_printf" ); return; } - ber_pvt_sb_udp_set_dst( sb, &m->m_clientaddr ); + ber_sockbuf_ctrl( sb, LBER_SB_OPT_UDP_SET_DST, + (void *)&m->m_clientaddr ); if ( ber_flush( sb, ber, 1 ) != 0 ) { send_ldap_msgresult( sb, SEARCHRESTAG, m, diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index a2231eb5ed..9a3b4feb56 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -16,9 +16,6 @@ #include "slap.h" -/* we need LBER internals */ -#include "../../libraries/liblber/lber-int.h" - /* protected by connections_mutex */ static ldap_pvt_thread_mutex_t connections_mutex; static Connection *connections = NULL; @@ -213,9 +210,12 @@ static Connection* connection_get( ber_socket_t s ) #else c = NULL; { - ber_socket_t i; + ber_socket_t i, sd; for(i=0; ic_mutex ); + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); if( c->c_struct_state != SLAP_C_USED ) { /* connection must have been closed due to resched */ assert( c->c_conn_state == SLAP_C_INVALID ); - assert( !ber_pvt_sb_in_use( c->c_sb ) ); + assert( sd == AC_SOCKET_INVALID ); Debug( LDAP_DEBUG_TRACE, "connection_get(%d): connection not used\n", @@ -265,7 +268,7 @@ static Connection* connection_get( ber_socket_t s ) assert( c->c_struct_state == SLAP_C_USED ); assert( c->c_conn_state != SLAP_C_INVALID ); - assert( ber_pvt_sb_in_use( c->c_sb ) ); + assert( sd != AC_SOCKET_INVALID ); c->c_activitytime = slap_get_time(); } @@ -323,6 +326,10 @@ long connection_init( c = NULL; for( i=0; i < dtblsize; i++) { + ber_socket_t sd; + + ber_sockbuf_ctrl( connections[i].c_sb, LBER_SB_OPT_GET_FD, &sd ); + if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) { assert( connections[i].c_sb == 0 ); c = &connections[i]; @@ -330,14 +337,14 @@ long connection_init( } if( connections[i].c_struct_state == SLAP_C_UNUSED ) { - assert( !ber_pvt_sb_in_use( connections[i].c_sb )); + assert( sd == AC_SOCKET_INVALID ); c = &connections[i]; break; } assert( connections[i].c_struct_state == SLAP_C_USED ); assert( connections[i].c_conn_state != SLAP_C_INVALID ); - assert( ber_pvt_sb_in_use( connections[i].c_sb )); + assert( sd != AC_SOCKET_INVALID ); } if( c == NULL ) { @@ -418,10 +425,14 @@ long connection_init( c->c_activitytime = c->c_starttime = slap_get_time(); - ber_pvt_sb_set_desc( c->c_sb, s ); - ber_pvt_sb_set_io( c->c_sb, &ber_pvt_sb_io_tcp, NULL ); - - if( ber_pvt_sb_set_nonblock( c->c_sb, 1 ) < 0 ) { + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp, LBER_SBIOD_LEVEL_PROVIDER, + (void *)&s ); + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_readahead, + LBER_SBIOD_LEVEL_PROVIDER, NULL ); +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, INT_MAX, NULL ); +#endif + if( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_NONBLOCK, (void *)1 ) < 0 ) { Debug( LDAP_DEBUG_ANY, "connection_init(%d, %s): set nonblocking failed\n", s, c->c_peer_name,0 ); @@ -454,6 +465,7 @@ static void connection_destroy( Connection *c ) { /* note: connections_mutex should be locked by caller */ + ber_socket_t sd; assert( connections != NULL ); assert( c != NULL ); @@ -527,18 +539,17 @@ connection_destroy( Connection *c ) c->c_currentber = NULL; } - if ( ber_pvt_sb_in_use(c->c_sb) ) { - int sd = ber_pvt_sb_get_desc(c->c_sb); - + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); + if ( sd != AC_SOCKET_INVALID ) { slapd_remove( sd, 0 ); - ber_pvt_sb_close( c->c_sb ); Statslog( LDAP_DEBUG_STATS, "conn=%ld fd=%d closed\n", c->c_connid, sd, 0, 0, 0 ); } - ber_pvt_sb_destroy( c->c_sb ); + ber_sockbuf_free( c->c_sb ); + c->c_sb = ber_sockbuf_alloc( ); c->c_conn_state = SLAP_C_INVALID; c->c_struct_state = SLAP_C_UNUSED; @@ -590,27 +601,32 @@ void connection_closing( Connection *c ) /* c_mutex must be locked by caller */ if( c->c_conn_state != SLAP_C_CLOSING ) { + ber_socket_t sd; + + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); Debug( LDAP_DEBUG_TRACE, "connection_closing: readying conn=%ld sd=%d for close\n", - c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 ); + c->c_connid, sd, 0 ); /* update state to closing */ c->c_conn_state = SLAP_C_CLOSING; /* don't listen on this port anymore */ - slapd_clr_read( ber_pvt_sb_get_desc( c->c_sb ), 1 ); + slapd_clr_read( sd, 1 ); /* abandon active operations */ connection_abandon( c ); /* wake write blocked operations */ - slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 ); + slapd_clr_write( sd, 1 ); ldap_pvt_thread_cond_signal( &c->c_write_cv ); } } static void connection_close( Connection *c ) { + ber_socket_t sd; + assert( connections != NULL ); assert( c != NULL ); assert( c->c_struct_state == SLAP_C_USED ); @@ -618,16 +634,17 @@ static void connection_close( Connection *c ) /* note: connections_mutex and c_mutex should be locked by caller */ + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); if( c->c_ops != NULL ) { Debug( LDAP_DEBUG_TRACE, "connection_close: deferring conn=%ld sd=%d\n", - c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 ); + c->c_connid, sd, 0 ); return; } Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d\n", - c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 ); + c->c_connid, sd, 0 ); connection_destroy( c ); } @@ -893,15 +910,14 @@ int connection_read(ber_socket_t s) * to propagate to client. */ FD_ZERO(&rfd); FD_SET(s, &rfd); - ber_pvt_sb_set_readahead(c->c_sb, 0); for (rc=1; rc>0;) { - char buf[4096]; tv.tv_sec = 1; tv.tv_usec = 0; rc = select(s+1, &rfd, NULL, NULL, &tv); if (rc == 1) - rc = ber_pvt_sb_read(c->c_sb, buf, sizeof(buf)); + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DRAIN, + NULL); } connection_close( c ); } else if ( rc == 0 ) { @@ -916,7 +932,7 @@ int connection_read(ber_socket_t s) #define CONNECTION_INPUT_LOOP 1 #ifdef DATA_READY_LOOP - while(!rc && ber_pvt_sb_data_ready(&c->c_sb)) + while( !rc && ber_sockbuf_ctrl( c->c_sb, LBER_SB_DATA_READY, NULL ) ) #elif CONNECTION_INPUT_LOOP while(!rc) #endif @@ -935,9 +951,9 @@ int connection_read(ber_socket_t s) connection_close( c ); } - if ( ber_pvt_sb_needs_read( c->c_sb ) ) + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) ) slapd_set_read( s, 1 ); - if ( ber_pvt_sb_needs_write( c->c_sb ) ) + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) slapd_set_write( s, 1 ); connection_return( c ); ldap_pvt_thread_mutex_unlock( &connections_mutex ); @@ -966,16 +982,13 @@ connection_input( != LDAP_TAG_MESSAGE ) { int err = errno; + ber_socket_t sd; + + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); Debug( LDAP_DEBUG_TRACE, "ber_get_next on fd %d failed errno=%d (%s)\n", - ber_pvt_sb_get_desc( conn->c_sb ), err, sock_errstr(err) ); - Debug( LDAP_DEBUG_TRACE, - "\t*** got %ld of %lu so far\n", - (long) ( conn->c_currentber->ber_buf - ? conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf - : 0 ), - (long) conn->c_currentber->ber_len, 0 ); + sd, err, sock_errstr(err) ); if ( err != EWOULDBLOCK && err != EAGAIN ) { /* log, close and send error */ @@ -1043,9 +1056,12 @@ connection_resched( Connection *conn ) Operation *op; if( conn->c_conn_state == SLAP_C_CLOSING ) { + ber_socket_t sd; + + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); Debug( LDAP_DEBUG_TRACE, "connection_resched: attempting closing conn=%ld sd=%d\n", - conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 ); + conn->c_connid, sd, 0 ); connection_close( conn ); return 0; @@ -1158,9 +1174,9 @@ int connection_write(ber_socket_t s) ldap_pvt_thread_cond_signal( &c->c_write_cv ); - if ( ber_pvt_sb_needs_read( c->c_sb ) ) + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) ) slapd_set_read( s, 1 ); - if ( ber_pvt_sb_needs_write( c->c_sb ) ) + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) slapd_set_write( s, 1 ); connection_return( c ); ldap_pvt_thread_mutex_unlock( &connections_mutex ); diff --git a/servers/slapd/result.c b/servers/slapd/result.c index d8bc0ffd18..75d30de43f 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -19,9 +19,6 @@ #include "slap.h" -/* we need LBER internals */ -#include "../../libraries/liblber/lber-int.h" - static char *v2ref( struct berval **ref, const char *text ) { size_t len = 0, i = 0; @@ -196,6 +193,7 @@ static long send_ldap_ber( /* write the pdu */ while( 1 ) { int err; + ber_socket_t sd; if ( connection_state_closing( conn ) ) { ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); @@ -230,7 +228,8 @@ static long send_ldap_ber( /* wait for socket to be write-ready */ conn->c_writewaiter = 1; - slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 ); + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); + slapd_set_write( sd, 1 ); ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex ); conn->c_writewaiter = 0; @@ -382,7 +381,8 @@ send_ldap_disconnect( #ifdef LDAP_CONNECTIONLESS if ( op->o_cldap ) { - ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr ); + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST, + (void *)&op->o_clientaddr ); Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", inet_ntoa(((struct sockaddr_in *) &op->o_clientaddr)->sin_addr ), @@ -453,7 +453,8 @@ send_ldap_result( #ifdef LDAP_CONNECTIONLESS if ( op->o_cldap ) { - ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr ); + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST, + (void *)&op->o_clientaddr ); Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", inet_ntoa(((struct sockaddr_in *) &op->o_clientaddr)->sin_addr ), @@ -499,7 +500,8 @@ send_ldap_sasl( #ifdef LDAP_CONNECTIONLESS if ( op->o_cldap ) { - ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr ); + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST, + (void *)&op->o_clientaddr ); Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", inet_ntoa(((struct sockaddr_in *) &op->o_clientaddr)->sin_addr ), @@ -540,7 +542,8 @@ send_ldap_extended( #ifdef LDAP_CONNECTIONLESS if ( op->o_cldap ) { - ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr ); + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST, + (void *)&op->o_clientaddr ); Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", inet_ntoa(((struct sockaddr_in *) &op->o_clientaddr)->sin_addr ), @@ -603,7 +606,8 @@ send_search_result( #ifdef LDAP_CONNECTIONLESS if ( op->o_cldap ) { - ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr ); + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST, + (void *)&op->o_clientaddr ); Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", inet_ntoa(((struct sockaddr_in *) &op->o_clientaddr)->sin_addr ), -- 2.39.5