1 /*	$NetBSD: io.c,v 1.3 2021/08/14 16:14:55 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-2021 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.3 2021/08/14 16:14:55 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
ber_skip_data(BerElement * ber,ber_len_t len)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
ber_read(BerElement * ber,char * buf,ber_len_t len)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
ber_write(BerElement * ber,LDAP_CONST char * buf,ber_len_t len,int zero)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
ber_realloc(BerElement * ber,ber_len_t len)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
ber_free_buf(BerElement * ber)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
ber_free(BerElement * ber,int freebuf)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
ber_flush(Sockbuf * sb,BerElement * ber,int freeit)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
ber_flush2(Sockbuf * sb,BerElement * ber,int freeit)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 *
ber_alloc_t(int options)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 *
ber_alloc(void)290 ber_alloc( void )	/* deprecated */
291 {
292 	return ber_alloc_t( 0 );
293 }
294 
295 BerElement *
der_alloc(void)296 der_alloc( void )	/* deprecated */
297 {
298 	return ber_alloc_t( LBER_USE_DER );
299 }
300 
301 BerElement *
ber_dup(BerElement * ber)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
ber_init2(BerElement * ber,struct berval * bv,int options)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
ber_init_w_nullc(BerElement * ber,int options)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 *
ber_init(struct berval * bv)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 */
ber_flatten2(BerElement * ber,struct berval * bv,int alloc)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 
ber_flatten(BerElement * ber,struct berval ** bvPtr)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
ber_reset(BerElement * ber,int was_writing)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
ber_get_next(Sockbuf * sb,ber_len_t * len,BerElement * ber)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 *
ber_start(BerElement * ber)696 ber_start( BerElement* ber )
697 {
698 	return ber->ber_buf;
699 }
700 
701 int
ber_len(BerElement * ber)702 ber_len( BerElement* ber )
703 {
704 	return ( ber->ber_end - ber->ber_buf );
705 }
706 
707 int
ber_ptrlen(BerElement * ber)708 ber_ptrlen( BerElement* ber )
709 {
710 	return ( ber->ber_ptr - ber->ber_buf );
711 }
712 
713 void
ber_rewind(BerElement * ber)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
ber_remaining(BerElement * ber)727 ber_remaining( BerElement * ber )
728 {
729 	return ber_pvt_ber_remaining( ber );
730 }
731