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