which only part of a LDAPMessage is available on a socket.
The server-code seemed to handle this correctly already, so I didn't touch
it.
My apologies for the hack in ber_get_next :-).
LDAP_F long ber_write LDAP_P(( BerElement *ber, char *buf, unsigned long len,
int nosos ));
LDAP_F void ber_free LDAP_P(( BerElement *ber, int freebuf ));
+LDAP_F void ber_clear LDAP_P(( BerElement *ber, int freebuf ));
LDAP_F int ber_flush LDAP_P(( Sockbuf *sb, BerElement *ber, int freeit ));
LDAP_F BerElement *ber_alloc LDAP_P(( void ));
LDAP_F BerElement *der_alloc LDAP_P(( void ));
/*
* LBER Sockbuf functions
*/
-LDAP_F Sockbuf *lber_pvt_sockbuf_alloc LDAP_P((void));
-LDAP_F Sockbuf *lber_pvt_sockbuf_alloc_fd LDAP_P((int fd));
-LDAP_F void lber_pvt_sockbuf_free LDAP_P((Sockbuf *sb));
+LDAP_F Sockbuf *lber_pvt_sk_alloc LDAP_P((void));
+LDAP_F Sockbuf *lber_pvt_sb_alloc_fd LDAP_P((int fd));
+LDAP_F void lber_pvt_sb_free LDAP_P((Sockbuf *sb));
LDAP_END_DECL
#include "lber-int.h"
+#ifdef LDAP_DEBUG
+#include <assert.h>
+#else
+#define assert(cond)
+#endif
+
static long BerRead LDAP_P(( Sockbuf *sb, char *buf, long len ));
static int ber_realloc LDAP_P(( BerElement *ber, unsigned long len ));
#define EXBUFSIZ 1024
+/* probably far too large... */
+#define MAX_BERBUFSIZE (128*1024)
+
+#if defined( DOS ) && !defined( _WIN32 ) && (MAX_BERBUFSIZE > 65535)
+# undef MAX_BERBUFSIZE
+# define MAX_BERBUFSIZE 65535
+#endif
+
static long
BerRead( Sockbuf *sb, char *buf, long len )
{
ber->ber_rwptr = NULL;
}
+#if 0
/* return the tag - LBER_DEFAULT returned means trouble */
static unsigned long
get_tag( Sockbuf *sb )
/* want leading, not trailing 0's */
return( tag >> (sizeof(long) - i - 1) );
}
+#endif
+
+/*
+ * A rewrite of get_get_next that can safely be called multiple times
+ * for the same packet. It will simply continue were it stopped until
+ * a full packet is read.
+ */
unsigned long
ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber )
{
- unsigned long tag = 0, netlen, toread;
- unsigned char lc;
- long rc;
- long noctets;
- unsigned int diff;
-
if ( ber->ber_debug ) {
lber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
"ber_get_next\n" );
}
-
+
/*
* Any ber element looks like this: tag length contents.
* Assuming everything's ok, we return the tag byte (we
* 2) definite lengths
* 3) primitive encodings used whenever possible
*/
+
+ if (ber->ber_rwptr == NULL) {
+ assert( ber->ber_buf == NULL );
+ ber->ber_rwptr = (char *) &ber->ber_tag;
+ ber->ber_tag = 0;
+ }
- /*
- * first time through - malloc the buffer, set up ptrs, and
- * read the tag and the length and as much of the rest as we can
- */
-
- if ( ber->ber_rwptr == NULL ) {
- /*
- * First, we read the tag.
- */
-
- if ( (tag = get_tag( sb )) == LBER_DEFAULT ) {
- return( LBER_DEFAULT );
- }
- ber->ber_tag = tag;
-
- /*
- * Next, read the length. The first byte contains the length
- * of the length. If bit 8 is set, the length is the long
- * form, otherwise it's the short form. We don't allow a
- * length that's greater than what we can hold in an unsigned
- * long.
- */
-
- *len = netlen = 0;
- if ( lber_pvt_sb_read( sb, (char *) &lc, 1 ) != 1 ) {
- return( LBER_DEFAULT );
+#define PTR_IN_VAR( ptr, var )\
+(((ptr)>=(char *) &(var)) && ((ptr)< (char *) &(var)+sizeof(var)))
+
+ if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag)) {
+ if (ber->ber_rwptr == (char *) &ber->ber_tag) {
+ if (lber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0)
+ return LBER_DEFAULT;
+ if ((ber->ber_rwptr[0] & LBER_BIG_TAG_MASK)
+ != LBER_BIG_TAG_MASK) {
+ ber->ber_tag = ber->ber_rwptr[0];
+ ber->ber_rwptr = (char *) &ber->ber_usertag;
+ goto get_lenbyte;
+ }
+ ber->ber_rwptr++;
}
- if ( lc & 0x80 ) {
- noctets = (lc & 0x7f);
- if ( noctets > sizeof(unsigned long) )
- return( LBER_DEFAULT );
- diff = sizeof(unsigned long) - noctets;
- if ( BerRead( sb, (char *) &netlen + diff, noctets ) !=
- noctets ) {
- return( LBER_DEFAULT );
+ do {
+ /* reading the tag... */
+ if (lber_pvt_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) -
+ ((char *) &ber->ber_tag - ber->ber_rwptr);
+ ber->ber_rwptr = (char *) &ber->ber_usertag;
+ goto get_lenbyte;
+ }
+ } while (PTR_IN_VAR(ber->ber_rwptr,ber->ber_tag));
+ errno = ERANGE; /* this is a serious error. */
+ return LBER_DEFAULT;
+ }
+get_lenbyte:
+ if (ber->ber_rwptr==(char *) &ber->ber_usertag) {
+ unsigned char c;
+ if (lber_pvt_sb_read( sb, (char *) &c, 1)<=0)
+ return LBER_DEFAULT;
+ if (c & 0x80) {
+ int len = c & 0x7f;
+ if ( (len==0) || ( len>sizeof( ber->ber_len ) ) ) {
+ errno = ERANGE;
+ return LBER_DEFAULT;
}
- *len = AC_NTOHL( netlen );
+ ber->ber_rwptr = (char *) &ber->ber_len +
+ sizeof(ber->ber_len) - len;
+ ber->ber_len = 0;
} else {
- *len = lc;
+ ber->ber_len = c;
+ goto fill_buffer;
}
- ber->ber_len = *len;
-
- /*
- * Finally, malloc a buffer for the contents and read it in.
- * It's this buffer that's passed to all the other ber decoding
- * routines.
- */
-
-#if defined( DOS ) && !defined( _WIN32 )
- if ( *len > 65535 ) { /* DOS can't allocate > 64K */
- return( LBER_DEFAULT );
- }
-#endif /* DOS && !_WIN32 */
-#ifdef DEADWOOD
- if ( ( sb->sb_options & LBER_MAX_INCOMING_SIZE ) &&
- *len > (unsigned long) sb->sb_max_incoming ) {
- return( LBER_DEFAULT );
+ }
+ if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_len)) {
+ int res;
+ int to_go;
+ to_go = (char *) &ber->ber_len + sizeof( ber->ber_len ) -
+ ber->ber_rwptr;
+ assert( to_go > 0 );
+ res = lber_pvt_sb_read( sb, ber->ber_rwptr, to_go );
+ if (res <=0)
+ return LBER_DEFAULT;
+ ber->ber_rwptr += res;
+ if (res==to_go) {
+ /* convert length. */
+ ber->ber_len = AC_NTOHL( ber->ber_len );
+ goto fill_buffer;
+ } else {
+#if defined( EWOULDBLOCK )
+ errno = EWOULDBLOCK;
+#elif defined( EAGAIN )
+ errno = EAGAIN;
+#endif
+ return LBER_DEFAULT;
}
-#endif
- if ( (ber->ber_buf = (char *) malloc( (size_t)*len )) == NULL ) {
- return( LBER_DEFAULT );
+ }
+fill_buffer:
+ /* now fill the buffer. */
+ if (ber->ber_buf==NULL) {
+ if (ber->ber_len > MAX_BERBUFSIZE) {
+ errno = ERANGE;
+ return LBER_DEFAULT;
}
- ber->ber_ptr = ber->ber_buf;
- ber->ber_end = ber->ber_buf + *len;
+ ber->ber_buf = (char *) malloc( ber->ber_len );
+ if (ber->ber_buf==NULL)
+ return LBER_DEFAULT;
ber->ber_rwptr = ber->ber_buf;
+ ber->ber_ptr = ber->ber_buf;
+ ber->ber_end = ber->ber_buf + ber->ber_len;
}
-
- toread = (unsigned long)ber->ber_end - (unsigned long)ber->ber_rwptr;
- do {
- if ( (rc = lber_pvt_sb_read( sb, ber->ber_rwptr, (long)toread )) <= 0 ) {
- return( LBER_DEFAULT );
+ if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) {
+ int res;
+ int to_go;
+
+ to_go = ber->ber_end - ber->ber_rwptr;
+ assert( to_go > 0 );
+
+ res = lber_pvt_sb_read( sb, ber->ber_rwptr, to_go );
+ if (res<=0)
+ return LBER_DEFAULT;
+ ber->ber_rwptr+=res;
+
+ if (res<to_go) {
+#if defined( EWOULDBLOCK )
+ errno = EWOULDBLOCK;
+#elif defined( EAGAIN )
+ errno = EAGAIN;
+#endif
+ return LBER_DEFAULT;
}
-
- toread -= rc;
- ber->ber_rwptr += rc;
- } while ( toread > 0 );
-
- if ( ber->ber_debug ) {
- lber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
- "ber_get_next: tag 0x%lx len %ld contents:\n",
- tag, ber->ber_len );
-
- lber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
+
+ ber->ber_rwptr = NULL;
+ *len = ber->ber_len;
+ if ( ber->ber_debug ) {
+ lber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
+ "ber_get_next: tag 0x%lx len %ld contents:\n",
+ ber->ber_tag, ber->ber_len );
+ lber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
+ }
+ return (ber->ber_tag);
}
+ assert( 0 ); /* ber structure is messed up ?*/
+ return LBER_DEFAULT;
+}
- *len = ber->ber_len;
+void ber_clear( BerElement *ber, int freebuf )
+{
+ if ((freebuf) && (ber->ber_buf))
+ free( ber->ber_buf );
+ ber->ber_buf = NULL;
ber->ber_rwptr = NULL;
- return( ber->ber_tag );
+ ber->ber_end = NULL;
}
Sockbuf *lber_pvt_sb_alloc( void )
#ifdef LDAP_DEBUG
#include <assert.h>
+#undef TEST_PARTIAL_READ
+#undef TEST_PARTIAL_WRITE
#else
#define assert( cond )
#endif
static int
grow_buffer( Sockbuf_Buf * buf, long minsize )
{
- /* round to nearest 2k */
- if (minsize < MIN_BUF_SIZE) {
- minsize = MIN_BUF_SIZE;
- } else {
- minsize=((minsize-1)|2047)+1;
- if (minsize > MAX_BUF_SIZE) {
+ long pw=MIN_BUF_SIZE;
+
+ for(;(pw<minsize);pw<<=1) {
+ if (pw > MAX_BUF_SIZE) {
/* this could mean that somebody is trying to crash us. */
return -1;
}
}
+ minsize = pw;
+
if (buf->buf_size<minsize) {
if ((buf->buf_base==NULL) || ((buf->buf_end==0) && (buf->buf_ptr==0))) {
/* empty buffer */
/* breaks slapd :-) */
assert( lber_pvt_sb_in_use( sb ) );
#endif
+
+#ifdef TEST_PARTIAL_READ
+ if ((rand() & 3)==1) { /* 1 out of 4 */
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+
+ len = (rand() % len)+1;
+#endif
buf = (char *) buf_arg;
- len = sockbuf_copy_out( sb, &buf, len );
-
- if (len==0) {
- return (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);
+ }
}
#ifdef USE_SASL
}
for(;;) {
/* read from stream into sb_sec_buf_in */
- ret = sockbuf_io_read( sb, sb->sb_sec_buf_in.buf_base +
+ 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;
long max;
max = sb->sb_buf.buf_size - sb->sb_buf.buf_end;
if (max>len) {
- ret = sockbuf_io_read( sb,
+ for(;;) {
+ ret = sockbuf_io_read( sb,
sb->sb_buf.buf_base +
sb->sb_buf.buf_end,
- max );
+ max );
+#ifdef EINTR
+ if ((ret<0) && (errno==EINTR))
+ continue;
+#endif
+ break;
+ }
if (ret<=0) {
/* some error occured */
goto do_return;
}
}
/* no read_ahead, just try to put the data in the buf. */
- ret = sockbuf_io_read( sb, buf, len );
+ 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;
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... */
- ret = sockbuf_io_write( sb, sb->sb_sec_out.buf_base+
- sb->sb_sec_out.buf_ptr, to_go );
+ 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;
+ }
if (ret<=0) /* error */
return ret;
sb->sb_sec_out.buf_ptr += ret;
/* unfortunately breaks slapd */
assert( lber_pvt_sb_in_use( sb ) );
#endif
+#ifdef TEST_PARTIAL_WRITE
+ if ((rand() & 3)==1) { /* 1 out of 4 */
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+
+ len_arg = (rand() % len_arg)+1;
+ len = len_arg;
+#endif
+
#ifdef USE_SASL
if (sb->sb_sec) {
assert( sb->sb_sec_prev_len <= len );
return len_arg;
} else {
#endif
- return sockbuf_io_write( sb, buf, len );
+ for(;;) {
+ ret = sockbuf_io_write( sb, buf, len );
+#ifdef EINTR
+ if ((ret<0) && (errno==EINTR))
+ continue;
+#endif
+ break;
+ }
#ifdef USE_SASL
}
#endif
LDAPServer *lconn_server;
char *lconn_krbinstance;
struct ldap_conn *lconn_next;
+ BerElement lconn_ber;/* ber receiving on this conn. */
} LDAPConn;
/* stuff used by connectionless searches. */
char *ld_cldapdn; /* DN used in connectionless search */
int ld_cldapnaddr; /* number of addresses */
- void **ld_cldapaddrs;/* addresses to send request to */
-
+ void **ld_cldapaddrs;/* addresses to send request to */
+#ifndef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
+ /* BerElement that this connection is receiving. */
+ BerElement ld_ber;
+#endif
/* do not mess with the rest though */
BERTranslateProc ld_lber_encode_translate_proc;
BERTranslateProc ld_lber_decode_translate_proc;
#include <ac/unistd.h>
#include "ldap-int.h"
+#include "lber.h"
#if defined( LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS ) || defined( LDAP_API_FEATURE_X_OPENLDAP_V2_DNS )
static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPServer *srv, int any ));
}
ldap_close_connection( lc->lconn_sb );
lber_pvt_sb_destroy( lc->lconn_sb );
+ ber_clear( &lc->lconn_ber, 1 );
}
prevlc = NULL;
for ( tmplc = ld->ld_conns; tmplc != NULL;
static int wait4msg LDAP_P(( LDAP *ld, int msgid, int all, struct timeval *timeout,
LDAPMessage **result ));
#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
-static int read1msg LDAP_P(( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
+static int try_read1msg LDAP_P(( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
LDAPMessage **result ));
static unsigned long build_result_ber LDAP_P(( LDAP *ld, BerElement *ber, LDAPRequest *lr ));
static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
#else /* LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
-static int read1msg LDAP_P(( LDAP *ld, int msgid, int all, Sockbuf *sb,
+static int try_read1msg LDAP_P(( LDAP *ld, int msgid, int all, Sockbuf *sb,
LDAPMessage **result ));
#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
#if defined( LDAP_CONNECTIONLESS ) || !defined( LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS )
if ( rc == -1 ) {
rc = -2; /* select interrupted: loop */
} else {
- rc = read1msg( ld, msgid, all, &ld->ld_sb, result );
+ rc = try_read1msg( ld, msgid, all, &ld->ld_sb, result );
}
#else /* !LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
#ifdef LDAP_DEBUG
#endif /* LDAP_DEBUG */
for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
if ( lber_pvt_sb_data_ready(lc->lconn_sb) ) {
- rc = read1msg( ld, msgid, all, lc->lconn_sb,
+ rc = try_read1msg( ld, msgid, all, lc->lconn_sb,
lc, result );
break;
}
LDAP_CONNST_CONNECTED &&
ldap_is_read_ready( ld,
lc->lconn_sb )) {
- rc = read1msg( ld, msgid, all,
+ rc = try_read1msg( ld, msgid, all,
lc->lconn_sb, lc, result );
}
}
static int
-read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
+try_read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
LDAPConn *lc,
#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
LDAPMessage **result )
{
- BerElement ber;
+ BerElement *ber;
LDAPMessage *new, *l, *prev, *tmp;
long id;
unsigned long tag, len;
BerElement tmpber;
int rc, refer_cnt, hadref, simple_request;
unsigned long lderr;
+
+ ber = &lc->lconn_ber;
+#else
+ ber = &ld->ld_ber;
#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
Debug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
-
+#if 0
ber_init_w_nullc( &ber, 0 );
ldap_set_ber_options( ld, &ber );
-
+#endif
/* get the next message */
- if ( (tag = ber_get_next( sb, &len, &ber ))
+ if ( (tag = ber_get_next( sb, &len, ber ))
!= LDAP_TAG_MESSAGE ) {
- ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
- LDAP_LOCAL_ERROR);
- return( -1 );
+ if ( tag == LBER_DEFAULT) {
+#ifdef LDAP_DEBUG
+ Debug( LDAP_DEBUG_CONNS,
+ "ber_get_next failed.\n", 0, 0, 0 );
+#endif
+#ifdef EWOULDBLOCK
+ if (errno==EWOULDBLOCK) return -2;
+#endif
+#ifdef EAGAIN
+ if (errno == EAGAIN) return -2;
+#endif
+ ld->ld_errno = LDAP_SERVER_DOWN;
+ return -1;
+ }
+ ld->ld_errno = LDAP_LOCAL_ERROR;
+ return -1;
}
/* message id */
- if ( ber_get_int( &ber, &id ) == LBER_ERROR ) {
+ if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
ld->ld_errno = LDAP_DECODING_ERROR;
return( -1 );
}
/* if it's been abandoned, toss it */
if ( ldap_abandoned( ld, (int)id ) ) {
- free( ber.ber_buf ); /* gack! */
+ ber_clear( ber, 1 ); /* gack! */
return( -2 ); /* continue looking */
}
Debug( LDAP_DEBUG_ANY,
"no request for response with msgid %ld (tossing)\n",
id, 0, 0 );
- free( ber.ber_buf ); /* gack! */
+ ber_clear( ber, 1 ); /* gack! */
return( -2 ); /* continue looking */
}
Debug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
/* the message type */
- if ( (tag = ber_peek_tag( &ber, &len )) == LBER_ERROR ) {
+ if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
ld->ld_errno = LDAP_DECODING_ERROR;
return( -1 );
}
( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS)
!= LDAP_OPT_OFF ) ) )
{
- tmpber = ber; /* struct copy */
+ tmpber = *ber; /* struct copy */
if ( ber_scanf( &tmpber, "{iaa}", &lderr,
&lr->lr_res_matched, &lr->lr_res_error )
!= LBER_ERROR ) {
"read1msg: %d new referrals\n", refer_cnt, 0, 0 );
if ( refer_cnt != 0 ) { /* chasing referrals */
- free( ber.ber_buf ); /* gack! */
- ber.ber_buf = NULL;
+ ber_clear( ber, 1 ); /* gack! */
if ( refer_cnt < 0 ) {
return( -1 ); /* fatal error */
}
simple_request = ( hadref ? 0 : 1 );
} else {
/* request with referrals or child request */
- free( ber.ber_buf ); /* gack! */
- ber.ber_buf = NULL;
+ ber_clear( ber, 1 ); /* gack! */
}
while ( lr->lr_parent != NULL ) {
lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
lr->lr_res_matched ? lr->lr_res_matched : "" );
if ( !simple_request ) {
- if ( ber.ber_buf != NULL ) {
- free( ber.ber_buf ); /* gack! */
- ber.ber_buf = NULL;
- }
- if ( build_result_ber( ld, &ber, lr )
+ ber_clear( ber, 1 ); /* gack! */
+ if ( build_result_ber( ld, ber, lr )
== LBER_ERROR ) {
ld->ld_errno = LDAP_NO_MEMORY;
rc = -1; /* fatal error */
}
}
- if ( ber.ber_buf == NULL ) {
+ if ( ber->ber_buf == NULL ) {
return( rc );
}
}
new->lm_msgid = (int)id;
new->lm_msgtype = tag;
- new->lm_ber = ber_dup( &ber );
+ new->lm_ber = ber_dup( ber );
+ ber_clear( ber, 0 ); /* don't kill buffer */
#ifndef LDAP_NOCACHE
if ( ld->ld_cache != NULL ) {
#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS
if ( ld->ld_selectinfo != NULL )
ldap_free_select_info( ld->ld_selectinfo );
+#else
+ ber_clear( &(ld->ld_ber), 1 );
#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
if ( ld->ld_options.ldo_defbase != NULL )