Home | History | Annotate | Line # | Download | only in liblber
      1 /*	$NetBSD: io.c,v 1.4 2025/09/05 21:16:20 christos Exp $	*/
      2 
      3 /* io.c - ber general i/o routines */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
     19  * All rights reserved.
     20  *
     21  * Redistribution and use in source and binary forms are permitted
     22  * provided that this notice is preserved and that due credit is given
     23  * to the University of Michigan at Ann Arbor. The name of the University
     24  * may not be used to endorse or promote products derived from this
     25  * software without specific prior written permission. This software
     26  * is provided ``as is'' without express or implied warranty.
     27  */
     28 /* ACKNOWLEDGEMENTS:
     29  * This work was originally developed by the University of Michigan
     30  * (as part of U-MICH LDAP).
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __RCSID("$NetBSD: io.c,v 1.4 2025/09/05 21:16:20 christos Exp $");
     35 
     36 #include "portable.h"
     37 
     38 #include <stdio.h>
     39 
     40 #include <ac/stdlib.h>
     41 
     42 #include <ac/ctype.h>
     43 #include <ac/errno.h>
     44 #include <ac/socket.h>
     45 #include <ac/string.h>
     46 #include <ac/unistd.h>
     47 
     48 #ifdef HAVE_IO_H
     49 #include <io.h>
     50 #endif
     51 
     52 #include "lber-int.h"
     53 #include "ldap_log.h"
     54 
     55 ber_slen_t
     56 ber_skip_data(
     57 	BerElement *ber,
     58 	ber_len_t len )
     59 {
     60 	ber_len_t	actuallen, nleft;
     61 
     62 	assert( ber != NULL );
     63 	assert( LBER_VALID( ber ) );
     64 
     65 	nleft = ber_pvt_ber_remaining( ber );
     66 	actuallen = nleft < len ? nleft : len;
     67 	ber->ber_ptr += actuallen;
     68 	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
     69 
     70 	return( (ber_slen_t) actuallen );
     71 }
     72 
     73 /*
     74  * Read from the ber buffer.  The caller must maintain ber->ber_tag.
     75  * Do not use to read whole tags.  See ber_get_tag() and ber_skip_data().
     76  */
     77 ber_slen_t
     78 ber_read(
     79 	BerElement *ber,
     80 	char *buf,
     81 	ber_len_t len )
     82 {
     83 	ber_len_t	actuallen, nleft;
     84 
     85 	assert( ber != NULL );
     86 	assert( buf != NULL );
     87 	assert( LBER_VALID( ber ) );
     88 
     89 	nleft = ber_pvt_ber_remaining( ber );
     90 	actuallen = nleft < len ? nleft : len;
     91 
     92 	AC_MEMCPY( buf, ber->ber_ptr, actuallen );
     93 
     94 	ber->ber_ptr += actuallen;
     95 
     96 	return( (ber_slen_t) actuallen );
     97 }
     98 
     99 /*
    100  * Write to the ber buffer.
    101  * Note that ber_start_seqorset/ber_put_seqorset() bypass ber_write().
    102  */
    103 ber_slen_t
    104 ber_write(
    105 	BerElement *ber,
    106 	LDAP_CONST char *buf,
    107 	ber_len_t len,
    108 	int zero )	/* nonzero is unsupported from OpenLDAP 2.4.18 */
    109 {
    110 	char **p;
    111 
    112 	assert( ber != NULL );
    113 	assert( buf != NULL );
    114 	assert( LBER_VALID( ber ) );
    115 
    116 	if ( zero != 0 ) {
    117 		ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, "%s",
    118 			"ber_write: nonzero 4th argument not supported\n" );
    119 		return( -1 );
    120 	}
    121 
    122 	p = ber->ber_sos_ptr == NULL ? &ber->ber_ptr : &ber->ber_sos_ptr;
    123 	if ( len > (ber_len_t) (ber->ber_end - *p) ) {
    124 		if ( ber_realloc( ber, len ) != 0 ) return( -1 );
    125 	}
    126 	AC_MEMCPY( *p, buf, len );
    127 	*p += len;
    128 
    129 	return( (ber_slen_t) len );
    130 }
    131 
    132 /* Resize the ber buffer */
    133 int
    134 ber_realloc( BerElement *ber, ber_len_t len )
    135 {
    136 	ber_len_t	total, offset, sos_offset, rw_offset;
    137 	char		*buf;
    138 
    139 	assert( ber != NULL );
    140 	assert( LBER_VALID( ber ) );
    141 
    142 	/* leave room for ber_flatten() to \0-terminate ber_buf */
    143 	if ( ++len == 0 ) {
    144 		return( -1 );
    145 	}
    146 
    147 	total = ber_pvt_ber_total( ber );
    148 
    149 #define LBER_EXBUFSIZ	4060 /* a few words less than 2^N for binary buddy */
    150 #if defined( LBER_EXBUFSIZ ) && LBER_EXBUFSIZ > 0
    151 # ifndef notdef
    152 	/* don't realloc by small amounts */
    153 	total += len < LBER_EXBUFSIZ ? LBER_EXBUFSIZ : len;
    154 # else
    155 	{	/* not sure what value this adds.  reduce fragmentation? */
    156 		ber_len_t have = (total + (LBER_EXBUFSIZE - 1)) / LBER_EXBUFSIZ;
    157 		ber_len_t need = (len + (LBER_EXBUFSIZ - 1)) / LBER_EXBUFSIZ;
    158 		total = ( have + need ) * LBER_EXBUFSIZ;
    159 	}
    160 # endif
    161 #else
    162 	total += len;	/* realloc just what's needed */
    163 #endif
    164 
    165 	if ( total < len || total > (ber_len_t)-1 / 2 /* max ber_slen_t */ ) {
    166 		return( -1 );
    167 	}
    168 
    169 	buf = ber->ber_buf;
    170 	offset = ber->ber_ptr - buf;
    171 	sos_offset = ber->ber_sos_ptr ? ber->ber_sos_ptr - buf : 0;
    172 	/* if ber_sos_ptr != NULL, it is > ber_buf so that sos_offset > 0 */
    173 	rw_offset = ber->ber_rwptr ? ber->ber_rwptr - buf : 0;
    174 
    175 	buf = (char *) ber_memrealloc_x( buf, total, ber->ber_memctx );
    176 	if ( buf == NULL ) {
    177 		return( -1 );
    178 	}
    179 
    180 	ber->ber_buf = buf;
    181 	ber->ber_end = buf + total;
    182 	ber->ber_ptr = buf + offset;
    183 	if ( sos_offset )
    184 		ber->ber_sos_ptr = buf + sos_offset;
    185 	if ( ber->ber_rwptr )
    186 		ber->ber_rwptr = buf + rw_offset;
    187 
    188 	return( 0 );
    189 }
    190 
    191 void
    192 ber_free_buf( BerElement *ber )
    193 {
    194 	assert( LBER_VALID( ber ) );
    195 
    196 	if ( ber->ber_buf) ber_memfree_x( ber->ber_buf, ber->ber_memctx );
    197 
    198 	ber->ber_buf = NULL;
    199 	ber->ber_sos_ptr = NULL;
    200 	ber->ber_valid = LBER_UNINITIALIZED;
    201 }
    202 
    203 void
    204 ber_free( BerElement *ber, int freebuf )
    205 {
    206 	if( ber == NULL ) {
    207 		LDAP_MEMORY_DEBUG_ASSERT( ber != NULL );
    208 		return;
    209 	}
    210 
    211 	if( freebuf ) ber_free_buf( ber );
    212 
    213 	ber_memfree_x( (char *) ber, ber->ber_memctx );
    214 }
    215 
    216 int
    217 ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
    218 {
    219 	return ber_flush2( sb, ber,
    220 		freeit ? LBER_FLUSH_FREE_ON_SUCCESS
    221 			: LBER_FLUSH_FREE_NEVER );
    222 }
    223 
    224 int
    225 ber_flush2( Sockbuf *sb, BerElement *ber, int freeit )
    226 {
    227 	ber_len_t	towrite;
    228 	ber_slen_t	rc;
    229 
    230 	assert( sb != NULL );
    231 	assert( ber != NULL );
    232 	assert( SOCKBUF_VALID( sb ) );
    233 	assert( LBER_VALID( ber ) );
    234 
    235 	if ( ber->ber_rwptr == NULL ) {
    236 		ber->ber_rwptr = ber->ber_buf;
    237 	}
    238 	towrite = ber->ber_ptr - ber->ber_rwptr;
    239 
    240 	if ( sb->sb_debug ) {
    241 		ber_log_printf( LDAP_DEBUG_TRACE, sb->sb_debug,
    242 			"ber_flush2: %ld bytes to sd %ld%s\n",
    243 			towrite, (long) sb->sb_fd,
    244 			ber->ber_rwptr != ber->ber_buf ?  " (re-flush)" : "" );
    245 		ber_log_bprint( LDAP_DEBUG_BER, sb->sb_debug,
    246 			ber->ber_rwptr, towrite );
    247 	}
    248 
    249 	while ( towrite > 0 ) {
    250 #ifdef LBER_TRICKLE
    251 		sleep(1);
    252 		rc = ber_int_sb_write( sb, ber->ber_rwptr, 1 );
    253 #else
    254 		rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite );
    255 #endif
    256 		if ( rc <= 0 ) {
    257 			if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 );
    258 			return -1;
    259 		}
    260 		towrite -= rc;
    261 		ber->ber_rwptr += rc;
    262 	}
    263 
    264 	if ( freeit & LBER_FLUSH_FREE_ON_SUCCESS ) ber_free( ber, 1 );
    265 
    266 	return 0;
    267 }
    268 
    269 BerElement *
    270 ber_alloc_t( int options )
    271 {
    272 	BerElement	*ber;
    273 
    274 	ber = (BerElement *) LBER_CALLOC( 1, sizeof(BerElement) );
    275 
    276 	if ( ber == NULL ) {
    277 		return NULL;
    278 	}
    279 
    280 	ber->ber_valid = LBER_VALID_BERELEMENT;
    281 	ber->ber_tag = LBER_DEFAULT;
    282 	ber->ber_options = options;
    283 	ber->ber_debug = ber_int_debug;
    284 
    285 	assert( LBER_VALID( ber ) );
    286 	return ber;
    287 }
    288 
    289 BerElement *
    290 ber_alloc( void )	/* deprecated */
    291 {
    292 	return ber_alloc_t( 0 );
    293 }
    294 
    295 BerElement *
    296 der_alloc( void )	/* deprecated */
    297 {
    298 	return ber_alloc_t( LBER_USE_DER );
    299 }
    300 
    301 BerElement *
    302 ber_dup( BerElement *ber )
    303 {
    304 	BerElement	*new;
    305 
    306 	assert( ber != NULL );
    307 	assert( LBER_VALID( ber ) );
    308 
    309 	if ( (new = ber_alloc_t( ber->ber_options )) == NULL ) {
    310 		return NULL;
    311 	}
    312 
    313 	*new = *ber;
    314 
    315 	assert( LBER_VALID( new ) );
    316 	return( new );
    317 }
    318 
    319 
    320 void
    321 ber_init2( BerElement *ber, struct berval *bv, int options )
    322 {
    323 	assert( ber != NULL );
    324 
    325 	(void) memset( (char *)ber, '\0', sizeof( BerElement ));
    326 	ber->ber_valid = LBER_VALID_BERELEMENT;
    327 	ber->ber_tag = LBER_DEFAULT;
    328 	ber->ber_options = (char) options;
    329 	ber->ber_debug = ber_int_debug;
    330 
    331 	if ( bv != NULL ) {
    332 		ber->ber_buf = bv->bv_val;
    333 		ber->ber_ptr = ber->ber_buf;
    334 		ber->ber_end = ber->ber_buf + bv->bv_len;
    335 	}
    336 
    337 	assert( LBER_VALID( ber ) );
    338 }
    339 
    340 /* OLD U-Mich ber_init() */
    341 void
    342 ber_init_w_nullc( BerElement *ber, int options )
    343 {
    344 	ber_init2( ber, NULL, options );
    345 }
    346 
    347 /* New C-API ber_init() */
    348 /* This function constructs a BerElement containing a copy
    349 ** of the data in the bv argument.
    350 */
    351 BerElement *
    352 ber_init( struct berval *bv )
    353 {
    354 	BerElement *ber;
    355 
    356 	assert( bv != NULL );
    357 
    358 	if ( bv == NULL ) {
    359 		return NULL;
    360 	}
    361 
    362 	ber = ber_alloc_t( 0 );
    363 
    364 	if( ber == NULL ) {
    365 		/* allocation failed */
    366 		return NULL;
    367 	}
    368 
    369 	/* copy the data */
    370 	if ( ((ber_len_t) ber_write ( ber, bv->bv_val, bv->bv_len, 0 ))
    371 		!= bv->bv_len )
    372 	{
    373 		/* write failed, so free and return NULL */
    374 		ber_free( ber, 1 );
    375 		return NULL;
    376 	}
    377 
    378 	ber_reset( ber, 1 );	/* reset the pointer to the start of the buffer */
    379 	return ber;
    380 }
    381 
    382 /* New C-API ber_flatten routine */
    383 /* This routine allocates a struct berval whose contents are a BER
    384 ** encoding taken from the ber argument.  The bvPtr pointer points to
    385 ** the returned berval.
    386 **
    387 ** ber_flatten2 is the same, but uses a struct berval passed by
    388 ** the caller. If alloc is 0 the returned bv uses the ber buf directly.
    389 */
    390 int ber_flatten2(
    391 	BerElement *ber,
    392 	struct berval *bv,
    393 	int alloc )
    394 {
    395 	assert( bv != NULL );
    396 
    397 	if ( bv == NULL ) {
    398 		return -1;
    399 	}
    400 
    401 	if ( ber == NULL ) {
    402 		/* ber is null, create an empty berval */
    403 		bv->bv_val = NULL;
    404 		bv->bv_len = 0;
    405 
    406 	} else if ( ber->ber_sos_ptr != NULL ) {
    407 		/* unmatched "{" and "}" */
    408 		return -1;
    409 
    410 	} else {
    411 		/* copy the berval */
    412 		ber_len_t len = ber_pvt_ber_write( ber );
    413 
    414 		if ( alloc ) {
    415 			bv->bv_val = (char *) ber_memalloc_x( len + 1, ber->ber_memctx );
    416 			if ( bv->bv_val == NULL ) {
    417 				return -1;
    418 			}
    419 			AC_MEMCPY( bv->bv_val, ber->ber_buf, len );
    420 			bv->bv_val[len] = '\0';
    421 		} else if ( ber->ber_buf != NULL ) {
    422 			bv->bv_val = ber->ber_buf;
    423 			bv->bv_val[len] = '\0';
    424 		} else {
    425 			bv->bv_val = "";
    426 		}
    427 		bv->bv_len = len;
    428 	}
    429 	return 0;
    430 }
    431 
    432 int ber_flatten(
    433 	BerElement *ber,
    434 	struct berval **bvPtr)
    435 {
    436 	struct berval *bv;
    437 	int rc;
    438 
    439 	assert( bvPtr != NULL );
    440 
    441 	if(bvPtr == NULL) {
    442 		return -1;
    443 	}
    444 
    445 	bv = ber_memalloc_x( sizeof(struct berval), ber->ber_memctx );
    446 	if ( bv == NULL ) {
    447 		return -1;
    448 	}
    449 	rc = ber_flatten2(ber, bv, 1);
    450 	if (rc == -1) {
    451 		ber_memfree_x(bv, ber->ber_memctx);
    452 	} else {
    453 		*bvPtr = bv;
    454 	}
    455 	return rc;
    456 }
    457 
    458 void
    459 ber_reset( BerElement *ber, int was_writing )
    460 {
    461 	assert( ber != NULL );
    462 	assert( LBER_VALID( ber ) );
    463 
    464 	if ( was_writing ) {
    465 		ber->ber_end = ber->ber_ptr;
    466 		ber->ber_ptr = ber->ber_buf;
    467 
    468 	} else {
    469 		ber->ber_ptr = ber->ber_end;
    470 	}
    471 
    472 	ber->ber_rwptr = NULL;
    473 }
    474 
    475 /*
    476  * A rewrite of ber_get_next that can safely be called multiple times
    477  * for the same packet. It will simply continue where it stopped until
    478  * a full packet is read.
    479  */
    480 
    481 #define LENSIZE	4
    482 
    483 ber_tag_t
    484 ber_get_next(
    485 	Sockbuf *sb,
    486 	ber_len_t *len,
    487 	BerElement *ber )
    488 {
    489 	assert( sb != NULL );
    490 	assert( len != NULL );
    491 	assert( ber != NULL );
    492 	assert( SOCKBUF_VALID( sb ) );
    493 	assert( LBER_VALID( ber ) );
    494 
    495 	if ( ber->ber_debug & LDAP_DEBUG_TRACE ) {
    496 		ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
    497 			"ber_get_next\n" );
    498 	}
    499 
    500 	/*
    501 	 * Any ber element looks like this: tag length contents.
    502 	 * Assuming everything's ok, we return the tag byte (we
    503 	 * can assume a single byte), return the length in len,
    504 	 * and the rest of the undecoded element in buf.
    505 	 *
    506 	 * Assumptions:
    507 	 *	1) small tags (less than 128)
    508 	 *	2) definite lengths
    509 	 *	3) primitive encodings used whenever possible
    510 	 *
    511 	 * The code also handles multi-byte tags. The first few bytes
    512 	 * of the message are read to check for multi-byte tags and
    513 	 * lengths. These bytes are temporarily stored in the ber_tag,
    514 	 * ber_len, and ber_usertag fields of the berelement until
    515 	 * tag/len parsing is complete. After this parsing, any leftover
    516 	 * bytes and the rest of the message are copied into the ber_buf.
    517 	 *
    518 	 * We expect tag and len to be at most 32 bits wide.
    519 	 */
    520 
    521 	if (ber->ber_rwptr == NULL) {
    522 		assert( ber->ber_buf == NULL );
    523 		ber->ber_rwptr = (char *) &ber->ber_len-1;
    524 		ber->ber_ptr = ber->ber_rwptr;
    525 		ber->ber_tag = 0;
    526 	}
    527 
    528 	while (ber->ber_rwptr > (char *)&ber->ber_tag && ber->ber_rwptr <
    529 		(char *)&ber->ber_len + LENSIZE*2) {
    530 		ber_slen_t sblen;
    531 		char buf[sizeof(ber->ber_len)-1];
    532 		ber_len_t tlen = 0;
    533 
    534 		/* The tag & len can be at most 9 bytes; we try to read up to 8 here */
    535 		sock_errset(0);
    536 		sblen=((char *)&ber->ber_len + LENSIZE*2 - 1)-ber->ber_rwptr;
    537 		/* Trying to read the last len byte of a 9 byte tag+len */
    538 		if (sblen<1)
    539 			sblen = 1;
    540 		sblen=ber_int_sb_read( sb, ber->ber_rwptr, sblen );
    541 		if (sblen<=0) return LBER_DEFAULT;
    542 		ber->ber_rwptr += sblen;
    543 
    544 		/* We got at least one byte, try to parse the tag. */
    545 		if (ber->ber_ptr == (char *)&ber->ber_len-1) {
    546 			ber_tag_t tag;
    547 			unsigned char *p = (unsigned char *)ber->ber_ptr;
    548 			tag = *p++;
    549 			if ((tag & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK) {
    550 				ber_len_t i;
    551 				for (i=1; (char *)p<ber->ber_rwptr; i++) {
    552 					tag <<= 8;
    553 					tag |= *p++;
    554 					if (!(tag & LBER_MORE_TAG_MASK))
    555 						break;
    556 					/* Is the tag too big? */
    557 					if (i == sizeof(ber_tag_t)-1) {
    558 						sock_errset(ERANGE);
    559 						return LBER_DEFAULT;
    560 					}
    561 				}
    562 				/* Did we run out of bytes? */
    563 				if ((char *)p == ber->ber_rwptr) {
    564 					sock_errset(EWOULDBLOCK);
    565 					return LBER_DEFAULT;
    566 				}
    567 			}
    568 			ber->ber_tag = tag;
    569 			ber->ber_ptr = (char *)p;
    570 		}
    571 
    572 		if ( ber->ber_ptr == ber->ber_rwptr ) {
    573 			sock_errset(EWOULDBLOCK);
    574 			return LBER_DEFAULT;
    575 		}
    576 
    577 		/* Now look for the length */
    578 		if (*ber->ber_ptr & 0x80) {	/* multi-byte */
    579 			int i;
    580 			unsigned char *p = (unsigned char *)ber->ber_ptr;
    581 			int llen = *p++ & 0x7f;
    582 			if (llen > LENSIZE) {
    583 				sock_errset(ERANGE);
    584 				return LBER_DEFAULT;
    585 			}
    586 			/* Not enough bytes? */
    587 			if (ber->ber_rwptr - (char *)p < llen) {
    588 				sock_errset(EWOULDBLOCK);
    589 				return LBER_DEFAULT;
    590 			}
    591 			for (i=0; i<llen; i++) {
    592 				tlen <<=8;
    593 				tlen |= *p++;
    594 			}
    595 			ber->ber_ptr = (char *)p;
    596 		} else {
    597 			tlen = *(unsigned char *)ber->ber_ptr++;
    598 		}
    599 
    600 		/* Are there leftover data bytes inside ber->ber_len? */
    601 		if (ber->ber_ptr < (char *)&ber->ber_usertag) {
    602 			if (ber->ber_rwptr < (char *)&ber->ber_usertag) {
    603 				sblen = ber->ber_rwptr - ber->ber_ptr;
    604 			} else {
    605 				sblen = (char *)&ber->ber_usertag - ber->ber_ptr;
    606 			}
    607 			AC_MEMCPY(buf, ber->ber_ptr, sblen);
    608 			ber->ber_ptr += sblen;
    609 		} else {
    610 			sblen = 0;
    611 		}
    612 		ber->ber_len = tlen;
    613 
    614 		/* now fill the buffer. */
    615 
    616 		/* make sure length is reasonable */
    617 		if ( ber->ber_len == 0 ) {
    618 			sock_errset(ERANGE);
    619 			return LBER_DEFAULT;
    620 		}
    621 
    622 		if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) {
    623 			ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug,
    624 				"ber_get_next: sockbuf_max_incoming exceeded "
    625 				"(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming );
    626 			sock_errset(ERANGE);
    627 			return LBER_DEFAULT;
    628 		}
    629 
    630 		if (ber->ber_buf==NULL) {
    631 			ber_len_t l = ber->ber_rwptr - ber->ber_ptr;
    632 			/* ber->ber_ptr is always <= ber->ber->ber_rwptr.
    633 			 * make sure ber->ber_len agrees with what we've
    634 			 * already read.
    635 			 */
    636 			if ( ber->ber_len < sblen + l ) {
    637 				sock_errset(ERANGE);
    638 				return LBER_DEFAULT;
    639 			}
    640 			ber->ber_buf = (char *) ber_memalloc_x( ber->ber_len + 1, ber->ber_memctx );
    641 			if (ber->ber_buf==NULL) {
    642 				return LBER_DEFAULT;
    643 			}
    644 			ber->ber_end = ber->ber_buf + ber->ber_len;
    645 			if (sblen) {
    646 				AC_MEMCPY(ber->ber_buf, buf, sblen);
    647 			}
    648 			if (l > 0) {
    649 				AC_MEMCPY(ber->ber_buf + sblen, ber->ber_ptr, l);
    650 				sblen += l;
    651 			}
    652 			*ber->ber_end = '\0';
    653 			ber->ber_ptr = ber->ber_buf;
    654 			ber->ber_usertag = 0;
    655 			if ((ber_len_t)sblen == ber->ber_len) {
    656 				goto done;
    657 			}
    658 			ber->ber_rwptr = ber->ber_buf + sblen;
    659 		}
    660 	}
    661 
    662 	if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) {
    663 		ber_slen_t res;
    664 		ber_slen_t to_go;
    665 
    666 		to_go = ber->ber_end - ber->ber_rwptr;
    667 		/* unsigned/signed overflow */
    668 		if (to_go<0) return LBER_DEFAULT;
    669 
    670 		sock_errset(0);
    671 		res = ber_int_sb_read( sb, ber->ber_rwptr, to_go );
    672 		if (res<=0) return LBER_DEFAULT;
    673 		ber->ber_rwptr+=res;
    674 
    675 		if (res<to_go) {
    676 			sock_errset(EWOULDBLOCK);
    677 			return LBER_DEFAULT;
    678 		}
    679 done:
    680 		ber->ber_rwptr = NULL;
    681 		*len = ber->ber_len;
    682 		if ( ber->ber_debug ) {
    683 			ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
    684 				"ber_get_next: tag 0x%lx len %ld contents:\n",
    685 				ber->ber_tag, ber->ber_len );
    686 			ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
    687 		}
    688 		return (ber->ber_tag);
    689 	}
    690 
    691 	/* invalid input */
    692 	return LBER_DEFAULT;
    693 }
    694 
    695 char *
    696 ber_start( BerElement* ber )
    697 {
    698 	return ber->ber_buf;
    699 }
    700 
    701 int
    702 ber_len( BerElement* ber )
    703 {
    704 	return ( ber->ber_end - ber->ber_buf );
    705 }
    706 
    707 int
    708 ber_ptrlen( BerElement* ber )
    709 {
    710 	return ( ber->ber_ptr - ber->ber_buf );
    711 }
    712 
    713 void
    714 ber_rewind ( BerElement * ber )
    715 {
    716 	ber->ber_rwptr = NULL;
    717 	ber->ber_sos_ptr = NULL;
    718 	ber->ber_end = ber->ber_ptr;
    719 	ber->ber_ptr = ber->ber_buf;
    720 #if 0	/* TODO: Should we add this? */
    721 	ber->ber_tag = LBER_DEFAULT;
    722 	ber->ber_usertag = 0;
    723 #endif
    724 }
    725 
    726 int
    727 ber_remaining( BerElement * ber )
    728 {
    729 	return ber_pvt_ber_remaining( ber );
    730 }
    731