mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-18 11:05:48 +08:00
Added support in liblber and libldap for partial reads, i.e. situations in
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 :-).
This commit is contained in:
parent
7bac8381a6
commit
a81ca18845
@ -177,6 +177,7 @@ LDAP_F long ber_read LDAP_P(( BerElement *ber, char *buf, unsigned long len ));
|
||||
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 ));
|
||||
@ -205,9 +206,9 @@ lber_set_option LDAP_P((void *item, int option, void *invalue));
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
@ -32,11 +32,25 @@
|
||||
|
||||
#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 )
|
||||
{
|
||||
@ -329,6 +343,7 @@ ber_reset( BerElement *ber, int was_writing )
|
||||
ber->ber_rwptr = NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* return the tag - LBER_DEFAULT returned means trouble */
|
||||
static unsigned long
|
||||
get_tag( Sockbuf *sb )
|
||||
@ -363,21 +378,22 @@ 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
|
||||
@ -389,95 +405,140 @@ ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber )
|
||||
* 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 );
|
||||
}
|
||||
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 );
|
||||
#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;
|
||||
}
|
||||
*len = AC_NTOHL( netlen );
|
||||
ber->ber_rwptr++;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 );
|
||||
}
|
||||
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 /* DOS && !_WIN32 */
|
||||
#ifdef DEADWOOD
|
||||
if ( ( sb->sb_options & LBER_MAX_INCOMING_SIZE ) &&
|
||||
*len > (unsigned long) sb->sb_max_incoming ) {
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
if ( (ber->ber_buf = (char *) malloc( (size_t)*len )) == NULL ) {
|
||||
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 )
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
#ifdef LDAP_DEBUG
|
||||
#include <assert.h>
|
||||
#undef TEST_PARTIAL_READ
|
||||
#undef TEST_PARTIAL_WRITE
|
||||
#else
|
||||
#define assert( cond )
|
||||
#endif
|
||||
@ -112,16 +114,16 @@ packet_length( char *buf )
|
||||
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 */
|
||||
@ -309,13 +311,23 @@ lber_pvt_sb_read( Sockbuf *sb, void *buf_arg, long len )
|
||||
/* 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
|
||||
@ -336,8 +348,15 @@ lber_pvt_sb_read( Sockbuf *sb, void *buf_arg, long len )
|
||||
}
|
||||
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;
|
||||
@ -393,10 +412,17 @@ decode_packet:
|
||||
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;
|
||||
@ -408,7 +434,14 @@ decode_packet:
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
@ -433,8 +466,15 @@ long sockbuf_do_write( Sockbuf *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... */
|
||||
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;
|
||||
@ -453,6 +493,16 @@ long lber_pvt_sb_write( Sockbuf *sb, void *buf, long len_arg )
|
||||
/* 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 );
|
||||
@ -477,7 +527,14 @@ long lber_pvt_sb_write( Sockbuf *sb, void *buf, long len_arg )
|
||||
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
|
||||
|
@ -127,6 +127,7 @@ typedef struct ldap_conn {
|
||||
LDAPServer *lconn_server;
|
||||
char *lconn_krbinstance;
|
||||
struct ldap_conn *lconn_next;
|
||||
BerElement lconn_ber;/* ber receiving on this conn. */
|
||||
} LDAPConn;
|
||||
|
||||
|
||||
@ -227,8 +228,11 @@ struct ldap {
|
||||
/* 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;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#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 ));
|
||||
@ -444,6 +445,7 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
|
||||
}
|
||||
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;
|
||||
|
@ -28,12 +28,12 @@ static int ldap_mark_abandoned LDAP_P(( LDAP *ld, int msgid ));
|
||||
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 )
|
||||
@ -182,7 +182,7 @@ wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
|
||||
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
|
||||
@ -193,7 +193,7 @@ wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
|
||||
#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;
|
||||
}
|
||||
@ -232,7 +232,7 @@ wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
|
||||
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 );
|
||||
}
|
||||
}
|
||||
@ -259,13 +259,13 @@ wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
|
||||
|
||||
|
||||
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;
|
||||
@ -275,30 +275,47 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
|
||||
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 */
|
||||
}
|
||||
|
||||
@ -307,7 +324,7 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
|
||||
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",
|
||||
@ -317,7 +334,7 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
|
||||
#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 );
|
||||
}
|
||||
@ -334,7 +351,7 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
|
||||
( 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 ) {
|
||||
@ -365,8 +382,7 @@ Debug( LDAP_DEBUG_TRACE,
|
||||
"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 */
|
||||
}
|
||||
@ -377,8 +393,7 @@ Debug( LDAP_DEBUG_TRACE,
|
||||
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 ) {
|
||||
@ -400,11 +415,8 @@ Debug( LDAP_DEBUG_TRACE,
|
||||
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 */
|
||||
@ -420,7 +432,7 @@ lr->lr_res_matched ? lr->lr_res_matched : "" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ber.ber_buf == NULL ) {
|
||||
if ( ber->ber_buf == NULL ) {
|
||||
return( rc );
|
||||
}
|
||||
|
||||
@ -433,7 +445,8 @@ lr->lr_res_matched ? lr->lr_res_matched : "" );
|
||||
}
|
||||
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 ) {
|
||||
|
@ -91,6 +91,8 @@ ldap_ld_free( LDAP *ld, int close )
|
||||
#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 )
|
||||
|
Loading…
Reference in New Issue
Block a user