]> git.sur5r.net Git - openldap/blob - libraries/liblber/decode.c
aa33b44dad33a9b27520c950d260963d579ba36a
[openldap] / libraries / liblber / decode.c
1 /* decode.c - ber input decoding routines */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* Portions
7  * Copyright (c) 1990 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include <ac/stdarg.h>
24
25 #include <ac/string.h>
26 #include <ac/socket.h>
27
28 #include "lber-int.h"
29
30 static int ber_getnint LDAP_P(( BerElement *ber, long *num, int len ));
31
32 /* return the tag - LBER_DEFAULT returned means trouble */
33 unsigned long
34 ber_get_tag( BerElement *ber )
35 {
36         unsigned char   xbyte;
37         unsigned long   tag;
38         char            *tagp;
39         unsigned int    i;
40
41         assert( ber != NULL );
42
43         if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
44                 return( LBER_DEFAULT );
45
46         if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
47                 return( (unsigned long) xbyte );
48
49         tagp = (char *) &tag;
50         tagp[0] = xbyte;
51         for ( i = 1; i < sizeof(long); i++ ) {
52                 if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
53                         return( LBER_DEFAULT );
54
55                 tagp[i] = xbyte;
56
57                 if ( ! (xbyte & LBER_MORE_TAG_MASK) )
58                         break;
59         }
60
61         /* tag too big! */
62         if ( i == sizeof(long) )
63                 return( LBER_DEFAULT );
64
65         /* want leading, not trailing 0's */
66         return( tag >> (sizeof(long) - i - 1) );
67 }
68
69 unsigned long
70 ber_skip_tag( BerElement *ber, unsigned long *len )
71 {
72         unsigned long   tag;
73         unsigned char   lc;
74         unsigned int    noctets;
75         int             diff;
76         unsigned long   netlen;
77
78         assert( ber != NULL );
79         assert( len != NULL );
80
81         /*
82          * Any ber element looks like this: tag length contents.
83          * Assuming everything's ok, we return the tag byte (we
84          * can assume a single byte), and return the length in len.
85          *
86          * Assumptions:
87          *      1) definite lengths
88          *      2) primitive encodings used whenever possible
89          */
90
91         /*
92          * First, we read the tag.
93          */
94
95         if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT )
96                 return( LBER_DEFAULT );
97
98         /*
99          * Next, read the length.  The first byte contains the length of
100          * the length.  If bit 8 is set, the length is the long form,
101          * otherwise it's the short form.  We don't allow a length that's
102          * greater than what we can hold in an unsigned long.
103          */
104
105         *len = netlen = 0;
106         if ( ber_read( ber, (char *) &lc, 1 ) != 1 )
107                 return( LBER_DEFAULT );
108         if ( lc & 0x80U ) {
109                 noctets = (lc & 0x7fU);
110                 if ( (unsigned) noctets > sizeof(unsigned long) )
111                         return( LBER_DEFAULT );
112                 diff = sizeof(unsigned long) - noctets;
113                 if ( (unsigned) ber_read( ber, (char *) &netlen + diff, noctets )
114                     != noctets )
115                         return( LBER_DEFAULT );
116                 *len = AC_NTOHL( netlen );
117         } else {
118                 *len = lc;
119         }
120
121         return( tag );
122 }
123
124 unsigned long
125 ber_peek_tag(
126         LDAP_CONST BerElement *ber_in, /* not const per c-api-02 */
127         unsigned long *len )
128 {
129         unsigned long   tag;
130         BerElement *ber;
131
132         assert( ber_in != NULL );
133
134         ber = ber_dup( ber_in );
135
136         if( ber == NULL ) {
137                 return LBER_ERROR;
138         }
139
140         tag = ber_skip_tag( ber, len );
141
142         ber_free( ber, 0 );
143         return( tag );
144 }
145
146 static int
147 ber_getnint( BerElement *ber, long *num, int len )
148 {
149         int     diff, sign, i;
150         long    netnum;
151         char    *p;
152
153         assert( ber != NULL );
154         assert( num != NULL );
155
156         /*
157          * The tag and length have already been stripped off.  We should
158          * be sitting right before len bytes of 2's complement integer,
159          * ready to be read straight into an int.  We may have to sign
160          * extend after we read it in.
161          */
162
163         if ( (unsigned) len > sizeof(long) )
164                 return( -1 );
165
166         netnum = 0;
167         diff = sizeof(long) - len;
168         /* read into the low-order bytes of netnum */
169         if ( ber_read( ber, ((char *) &netnum) + diff, len ) != len )
170                 return( -1 );
171
172         /* sign extend if necessary */
173         p = (char *) &netnum;
174         sign = (0x80 & *(p+diff) );
175         if ( sign && ((unsigned) len < sizeof(long)) ) {
176                 for ( i = 0; i < diff; i++ ) {
177                         *(p+i) = (unsigned char) 0xff;
178                 }
179         }
180         *num = AC_NTOHL( netnum );
181
182         return( len );
183 }
184
185 unsigned long
186 ber_get_int( BerElement *ber, long *num )
187 {
188         unsigned long   tag, len;
189
190         assert( ber != NULL );
191
192         if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
193                 return( LBER_DEFAULT );
194
195         if ( (unsigned long) ber_getnint( ber, num, (int)len ) != len )
196                 return( LBER_DEFAULT );
197         else
198                 return( tag );
199 }
200
201 unsigned long
202 ber_get_stringb( BerElement *ber, char *buf, unsigned long *len )
203 {
204         unsigned long   datalen, tag;
205 #ifdef STR_TRANSLATION
206         char            *transbuf;
207 #endif /* STR_TRANSLATION */
208
209         assert( ber != NULL );
210
211         if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
212                 return( LBER_DEFAULT );
213         if ( datalen > (*len - 1) )
214                 return( LBER_DEFAULT );
215
216         if ( (unsigned long) ber_read( ber, buf, datalen ) != datalen )
217                 return( LBER_DEFAULT );
218
219         buf[datalen] = '\0';
220
221 #ifdef STR_TRANSLATION
222         if ( datalen > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
223             && ber->ber_decode_translate_proc ) {
224                 transbuf = buf;
225                 ++datalen;
226                 if ( (*(ber->ber_decode_translate_proc))( &transbuf, &datalen,
227                     0 ) != 0 ) {
228                         return( LBER_DEFAULT );
229                 }
230                 if ( datalen > *len ) {
231                         free( transbuf );
232                         return( LBER_DEFAULT );
233                 }
234                 SAFEMEMCPY( buf, transbuf, datalen );
235                 free( transbuf );
236                 --datalen;
237         }
238 #endif /* STR_TRANSLATION */
239
240         *len = datalen;
241         return( tag );
242 }
243
244 unsigned long
245 ber_get_stringa( BerElement *ber, char **buf )
246 {
247         unsigned long   datalen, tag;
248
249         assert( ber != NULL );
250         assert( buf != NULL );
251
252         if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) {
253                 *buf = NULL;
254                 return( LBER_DEFAULT );
255         }
256
257         if ( (*buf = (char *) malloc( (size_t)datalen + 1 )) == NULL )
258                 return( LBER_DEFAULT );
259
260         if ( (unsigned long) ber_read( ber, *buf, datalen ) != datalen ) {
261                 free( *buf );
262                 *buf = NULL;
263                 return( LBER_DEFAULT );
264         }
265         (*buf)[datalen] = '\0';
266
267 #ifdef STR_TRANSLATION
268         if ( datalen > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
269             && ber->ber_decode_translate_proc ) {
270                 ++datalen;
271                 if ( (*(ber->ber_decode_translate_proc))( buf, &datalen, 1 )
272                     != 0 ) {
273                         free( *buf );
274                         *buf = NULL;
275                         return( LBER_DEFAULT );
276                 }
277         }
278 #endif /* STR_TRANSLATION */
279
280         return( tag );
281 }
282
283 unsigned long
284 ber_get_stringal( BerElement *ber, struct berval **bv )
285 {
286         unsigned long   len, tag;
287
288         assert( ber != NULL );
289         assert( bv != NULL );
290
291         if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
292                 *bv = NULL;
293                 return( LBER_DEFAULT );
294         }
295
296         if ( (*bv = (struct berval *) malloc( sizeof(struct berval) )) == NULL )
297                 return( LBER_DEFAULT );
298
299         if ( ((*bv)->bv_val = (char *) malloc( (size_t)len + 1 )) == NULL ) {
300                 free( *bv );
301                 *bv = NULL;
302                 return( LBER_DEFAULT );
303         }
304
305         if ( (unsigned long) ber_read( ber, (*bv)->bv_val, len ) != len ) {
306                 ber_bvfree( *bv );
307                 *bv = NULL;
308                 return( LBER_DEFAULT );
309         }
310         ((*bv)->bv_val)[len] = '\0';
311         (*bv)->bv_len = len;
312
313 #ifdef STR_TRANSLATION
314         if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
315             && ber->ber_decode_translate_proc ) {
316                 ++len;
317                 if ( (*(ber->ber_decode_translate_proc))( &((*bv)->bv_val),
318                     &len, 1 ) != 0 ) {
319                         ber_bvfree( *bv );
320                         *bv = NULL;
321                         return( LBER_DEFAULT );
322                 }
323                 (*bv)->bv_len = len - 1;
324         }
325 #endif /* STR_TRANSLATION */
326
327         return( tag );
328 }
329
330 unsigned long
331 ber_get_bitstringa( BerElement *ber, char **buf, unsigned long *blen )
332 {
333         unsigned long   datalen, tag;
334         unsigned char   unusedbits;
335
336         assert( ber != NULL );
337         assert( buf != NULL );
338         assert( blen != NULL );
339
340         if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) {
341                 *buf = NULL;
342                 return( LBER_DEFAULT );
343         }
344         --datalen;
345
346         if ( (*buf = (char *) malloc( (size_t)datalen )) == NULL )
347                 return( LBER_DEFAULT );
348
349         if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 ) {
350                 free( buf );
351                 *buf = NULL;
352                 return( LBER_DEFAULT );
353         }
354
355         if ( (unsigned long) ber_read( ber, *buf, datalen ) != datalen ) {
356                 free( buf );
357                 *buf = NULL;
358                 return( LBER_DEFAULT );
359         }
360
361         *blen = datalen * 8 - unusedbits;
362         return( tag );
363 }
364
365 unsigned long
366 ber_get_null( BerElement *ber )
367 {
368         unsigned long   len, tag;
369
370         assert( ber != NULL );
371
372         if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
373                 return( LBER_DEFAULT );
374
375         if ( len != 0 )
376                 return( LBER_DEFAULT );
377
378         return( tag );
379 }
380
381 unsigned long
382 ber_get_boolean( BerElement *ber, int *boolval )
383 {
384         long    longbool;
385         int     rc;
386
387         assert( ber != NULL );
388         assert( boolval != NULL );
389
390         rc = ber_get_int( ber, &longbool );
391         *boolval = longbool;
392
393         return( rc );
394 }
395
396 unsigned long
397 ber_first_element( BerElement *ber, unsigned long *len, char **last )
398 {
399         assert( ber != NULL );
400         assert( len != NULL );
401         assert( last != NULL );
402
403         /* skip the sequence header, use the len to mark where to stop */
404         if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
405                 *last = NULL;
406                 return( LBER_DEFAULT );
407         }
408
409         *last = ber->ber_ptr + *len;
410
411         if ( *last == ber->ber_ptr ) {
412 #ifdef LBER_END_SEQORSET 
413                 return( LBER_END_SEQORSET );
414 #else
415                 return( LBER_DEFAULT );
416 #endif
417         }
418
419         return( ber_peek_tag( ber, len ) );
420 }
421
422 unsigned long
423 ber_next_element( BerElement *ber, unsigned long *len, char *last )
424 {
425         assert( ber != NULL );
426         assert( len != NULL );
427         assert( last != NULL );
428
429         if ( ber->ber_ptr == last ) {
430 #ifdef LBER_END_SEQORSET 
431                 return( LBER_END_SEQORSET );
432 #else
433                 return( LBER_DEFAULT );
434 #endif
435         }
436
437         return( ber_peek_tag( ber, len ) );
438 }
439
440 /* VARARGS */
441 unsigned long
442 ber_scanf
443 #if HAVE_STDARG
444         ( BerElement *ber,
445         LDAP_CONST char *fmt,
446         ... )
447 #else
448         ( va_alist )
449 va_dcl
450 #endif
451 {
452         va_list         ap;
453 #ifndef HAVE_STDARG
454         BerElement      *ber;
455         char            *fmt;
456 #endif
457         LDAP_CONST char         *fmt_reset;
458         char            *last;
459         char            *s, **ss, ***sss;
460         struct berval   ***bv, **bvp, *bval;
461         int             *i, j;
462         long            *l;
463         unsigned long   rc, tag, len;
464
465 #ifdef HAVE_STDARG
466         va_start( ap, fmt );
467 #else
468         va_start( ap );
469         ber = va_arg( ap, BerElement * );
470         fmt = va_arg( ap, char * );
471 #endif
472
473         assert( ber != NULL );
474         assert( fmt != NULL );
475
476         fmt_reset = fmt;
477
478         ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
479                 "ber_scanf fmt (%s) ber:\n", fmt );
480         ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
481
482         for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) {
483                 /* When this is modified, remember to update
484                  * the error-cleanup code below accordingly. */
485                 switch ( *fmt ) {
486                 case '!': { /* Hook */
487                                 BERDecodeCallback *f;
488                                 void *p;
489
490                                 f = va_arg( ap, BERDecodeCallback * );
491                                 p = va_arg( ap, void * );
492
493                                 rc = (*f)( ber, p, 0 );
494                         } break;
495
496                 case 'a':       /* octet string - allocate storage as needed */
497                         ss = va_arg( ap, char ** );
498                         rc = ber_get_stringa( ber, ss );
499                         break;
500
501                 case 'b':       /* boolean */
502                         i = va_arg( ap, int * );
503                         rc = ber_get_boolean( ber, i );
504                         break;
505
506                 case 'e':       /* enumerated */
507                 case 'i':       /* int */
508                         l = va_arg( ap, long * );
509                         rc = ber_get_int( ber, l );
510                         break;
511
512                 case 'l':       /* length of next item */
513                         l = va_arg( ap, long * );
514                         rc = ber_peek_tag( ber, l );
515                         break;
516
517                 case 'n':       /* null */
518                         rc = ber_get_null( ber );
519                         break;
520
521                 case 's':       /* octet string - in a buffer */
522                         s = va_arg( ap, char * );
523                         l = va_arg( ap, long * );
524                         rc = ber_get_stringb( ber, s, l );
525                         break;
526
527                 case 'o':       /* octet string in a supplied berval */
528                         bval = va_arg( ap, struct berval * );
529                         ber_peek_tag( ber, &bval->bv_len );
530                         rc = ber_get_stringa( ber, &bval->bv_val );
531                         break;
532
533                 case 'O':       /* octet string - allocate & include length */
534                         bvp = va_arg( ap, struct berval ** );
535                         rc = ber_get_stringal( ber, bvp );
536                         break;
537
538                 case 'B':       /* bit string - allocate storage as needed */
539                         ss = va_arg( ap, char ** );
540                         l = va_arg( ap, long * ); /* for length, in bits */
541                         rc = ber_get_bitstringa( ber, ss, l );
542                         break;
543
544                 case 't':       /* tag of next item */
545                         l = va_arg( ap, long * );
546                         *l = rc = ber_peek_tag( ber, &len );
547                         break;
548
549                 case 'T':       /* skip tag of next item */
550                         l = va_arg( ap, long * );
551                         *l = rc = ber_skip_tag( ber, &len );
552                         break;
553
554                 case 'v':       /* sequence of strings */
555                         sss = va_arg( ap, char *** );
556                         *sss = NULL;
557                         j = 0;
558                         for ( tag = ber_first_element( ber, &len, &last );
559                             tag != LBER_DEFAULT && 
560 #ifdef LBER_END_SEQORSET
561                                         tag != LBER_END_SEQORSET &&
562 #endif
563                                         rc != LBER_DEFAULT;
564                             tag = ber_next_element( ber, &len, last ) )
565                         {
566                                 if ( *sss == NULL ) {
567                                         *sss = (char **) malloc(
568                                             2 * sizeof(char *) );
569                                 } else {
570                                         *sss = (char **) realloc( *sss,
571                                             (j + 2) * sizeof(char *) );
572                                 }
573                                 rc = ber_get_stringa( ber, &((*sss)[j]) );
574                                 j++;
575                         }
576 #ifdef LBER_END_SEQORSET
577                         if (rc != LBER_DEFAULT && 
578                                 tag != LBER_END_SEQORSET )
579                         {
580                                 rc = LBER_DEFAULT;
581                         }
582 #endif
583                         if ( j > 0 )
584                                 (*sss)[j] = NULL;
585                         break;
586
587                 case 'V':       /* sequence of strings + lengths */
588                         bv = va_arg( ap, struct berval *** );
589                         *bv = NULL;
590                         j = 0;
591                         for ( tag = ber_first_element( ber, &len, &last );
592                             tag != LBER_DEFAULT && 
593 #ifdef LBER_END_SEQORSET
594                                         tag != LBER_END_SEQORSET &&
595 #endif
596                                         rc != LBER_DEFAULT;
597                             tag = ber_next_element( ber, &len, last ) )
598                         {
599                                 if ( *bv == NULL ) {
600                                         *bv = (struct berval **) malloc(
601                                             2 * sizeof(struct berval *) );
602                                 } else {
603                                         *bv = (struct berval **) realloc( *bv,
604                                             (j + 2) * sizeof(struct berval *) );
605                                 }
606                                 rc = ber_get_stringal( ber, &((*bv)[j]) );
607                                 j++;
608                         }
609 #ifdef LBER_END_SEQORSET
610                         if (rc != LBER_DEFAULT && 
611                                 tag != LBER_END_SEQORSET )
612                         {
613                                 rc = LBER_DEFAULT;
614                         }
615 #endif
616                         if ( j > 0 )
617                                 (*bv)[j] = NULL;
618                         break;
619
620                 case 'x':       /* skip the next element - whatever it is */
621                         if ( (rc = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
622                                 break;
623                         ber->ber_ptr += len;
624                         break;
625
626                 case '{':       /* begin sequence */
627                 case '[':       /* begin set */
628                         if ( *(fmt + 1) != 'v' && *(fmt + 1) != 'V' )
629                                 rc = ber_skip_tag( ber, &len );
630                         break;
631
632                 case '}':       /* end sequence */
633                 case ']':       /* end set */
634                         break;
635
636                 default:
637                         if( ber->ber_debug ) {
638                                 ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
639                                         "ber_scanf: unknown fmt %c\n", *fmt );
640                         }
641                         rc = LBER_DEFAULT;
642                         break;
643                 }
644         }
645
646         va_end( ap );
647
648         if ( rc == LBER_DEFAULT ) {
649             /*
650              * Error.  Reclaim malloced memory that was given to the caller.
651              * Set allocated pointers to NULL, "data length" outvalues to 0.
652              */
653 #ifdef HAVE_STDARG
654             va_start( ap, fmt );
655 #else
656             va_start( ap );
657             (void) va_arg( ap, BerElement * );
658             (void) va_arg( ap, char * );
659 #endif
660
661             for ( ; fmt_reset < fmt; fmt_reset++ ) {
662                 switch ( *fmt_reset ) {
663                 case '!': { /* Hook */
664                                 BERDecodeCallback *f;
665                                 void *p;
666
667                                 f = va_arg( ap, BERDecodeCallback * );
668                                 p = va_arg( ap, void * );
669
670                                 (void) (*f)( ber, p, 1 );
671                         } break;
672
673                 case 'a':       /* octet string - allocate storage as needed */
674                         ss = va_arg( ap, char ** );
675                         if ( *ss ) {
676                                 free( *ss );
677                                 *ss = NULL;
678                         }
679                         break;
680
681                 case 'b':       /* boolean */
682                         (void) va_arg( ap, int * );
683                         break;
684
685                 case 's':       /* octet string - in a buffer */
686                         (void) va_arg( ap, char * );
687                         (void) va_arg( ap, long * );
688                         break;
689
690                 case 'e':       /* enumerated */
691                 case 'i':       /* int */
692                 case 'l':       /* length of next item */
693                 case 't':       /* tag of next item */
694                 case 'T':       /* skip tag of next item */
695                         (void) va_arg( ap, long * );
696                         break;
697
698                 case 'o':       /* octet string in a supplied berval */
699                         bval = va_arg( ap, struct berval * );
700                         if ( bval->bv_val != NULL ) {
701                                 free( bval->bv_val );
702                                 bval->bv_val = NULL;
703                         }
704                         bval->bv_len = 0;
705                         break;
706
707                 case 'O':       /* octet string - allocate & include length */
708                         bvp = va_arg( ap, struct berval ** );
709                         if ( *bvp ) {
710                                 ber_bvfree( *bvp );
711                                 *bvp = NULL;
712                         }
713                         break;
714
715                 case 'B':       /* bit string - allocate storage as needed */
716                         ss = va_arg( ap, char ** );
717                         if ( *ss ) {
718                                 free( *ss );
719                                 *ss = NULL;
720                         }
721                         *(va_arg( ap, long * )) = 0; /* for length, in bits */
722                         break;
723
724                 case 'v':       /* sequence of strings */
725                         sss = va_arg( ap, char *** );
726                         if ( *sss ) {
727                                 for (j = 0;  (*sss)[j];  j++) {
728                                         free( (*sss)[j] );
729                                         (*sss)[j] = NULL;
730                                 }
731                                 free( *sss );
732                                 *sss = NULL;
733                         }
734                         break;
735
736                 case 'V':       /* sequence of strings + lengths */
737                         bv = va_arg( ap, struct berval *** );
738                         if ( *bv ) {
739                                 ber_bvecfree( *bv );
740                                 *bv = NULL;
741                         }
742                         break;
743
744                 case 'n':       /* null */
745                 case 'x':       /* skip the next element - whatever it is */
746                 case '{':       /* begin sequence */
747                 case '[':       /* begin set */
748                 case '}':       /* end sequence */
749                 case ']':       /* end set */
750                         break;
751
752                 default:
753                         /* format should be good */
754                         assert( 0 );
755                 }
756             }
757
758             va_end( ap );
759         }
760
761         return( rc );
762 }
763
764 void
765 ber_bvfree( struct berval *bv )
766 {
767         assert(bv != NULL);                     /* bv damn better point to something */
768
769         if ( bv->bv_val != NULL )
770                 free( bv->bv_val );
771         free( (char *) bv );
772 }
773
774 void
775 ber_bvecfree( struct berval **bv )
776 {
777         int     i;
778
779         assert(bv != NULL);                     /* bv damn better point to something */
780
781         for ( i = 0; bv[i] != NULL; i++ )
782                 ber_bvfree( bv[i] );
783         free( (char *) bv );
784 }
785
786 struct berval *
787 ber_bvdup(
788         LDAP_CONST struct berval *bv )
789 {
790         struct berval   *new;
791
792         assert( bv != NULL );
793
794         if( bv == NULL ) {
795                 return NULL;
796         }
797
798         if ( (new = (struct berval *) malloc( sizeof(struct berval) ))
799             == NULL ) {
800                 return( NULL );
801         }
802
803         if ( bv->bv_val == NULL ) {
804                 new->bv_val = NULL;
805                 new->bv_len = 0;
806                 return ( new );
807         }
808
809         if ( (new->bv_val = (char *) malloc( bv->bv_len + 1 )) == NULL ) {
810                 free( new );
811                 return( NULL );
812         }
813
814         SAFEMEMCPY( new->bv_val, bv->bv_val, (size_t) bv->bv_len );
815         new->bv_val[bv->bv_len] = '\0';
816         new->bv_len = bv->bv_len;
817
818         return( new );
819 }
820
821
822 #ifdef STR_TRANSLATION
823 void
824 ber_set_string_translators( BerElement *ber, BERTranslateProc encode_proc,
825         BERTranslateProc decode_proc )
826 {
827         assert( ber != NULL );
828
829     ber->ber_encode_translate_proc = encode_proc;
830     ber->ber_decode_translate_proc = decode_proc;
831 }
832 #endif /* STR_TRANSLATION */