]> git.sur5r.net Git - openldap/blob - decode.c
3b8516e6ea235b9f5cdc974f20719ec141e349df
[openldap] / decode.c
1 /* decode.c - ber input decoding routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2007 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26 /* ACKNOWLEDGEMENTS:
27  * This work was originally developed by the University of Michigan
28  * (as part of U-MICH LDAP).
29  */
30
31 #include "portable.h"
32
33 #include <stdio.h>
34
35 #include <ac/stdlib.h>
36
37 #include <ac/stdarg.h>
38 #include <ac/string.h>
39 #include <ac/socket.h>
40
41 #include "lber-int.h"
42
43 static ber_len_t ber_getnint LDAP_P((
44         BerElement *ber,
45         ber_int_t *num,
46         ber_len_t len ));
47
48 /* out->bv_len should be the buffer size on input */
49 int
50 ber_decode_oid( BerValue *in, BerValue *out )
51 {
52         unsigned char *der = in->bv_val;
53         unsigned long val, val1;
54         int i, len;
55         char *ptr;
56
57         assert( in != NULL );
58         assert( out != NULL );
59
60         /* expands by 5/2, and we add dots - call it 3 */
61         if ( !out->bv_val || out->bv_len < in->bv_len * 3 )
62                 return -1;
63
64         val1 = der[0] / 40;
65         val = der[0] - val1 * 40;
66
67         len = sprintf( out->bv_val, "%ld.%ld", val1, val );
68         ptr = out->bv_val + len;
69         val = 0;
70         for ( i=1; i<in->bv_len; i++ ) {
71                 val = val << 7;
72                 val |= der[i] & 0x7f;
73                 if ( !( der[i] & 0x80 )) {
74                         ptr += sprintf( ptr, ".%ld", val );
75                         val = 0;
76                 }
77         }
78         out->bv_len = ptr - out->bv_val;
79         return 0;
80 }
81
82 /* return the tag - LBER_DEFAULT returned means trouble */
83 ber_tag_t
84 ber_get_tag( BerElement *ber )
85 {
86         unsigned char   xbyte;
87         ber_tag_t       tag;
88         unsigned int    i;
89
90         assert( ber != NULL );
91         assert( LBER_VALID( ber ) );
92
93         if ( ber_pvt_ber_remaining( ber ) < 1 ) {
94                 return LBER_DEFAULT;
95         }
96
97         if ( ber->ber_ptr == ber->ber_buf ) {
98                 tag = *(unsigned char *)ber->ber_ptr;
99         } else {
100                 tag = ber->ber_tag;
101         }
102         ber->ber_ptr++;
103
104         if ( (tag & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
105                 return tag;
106         }
107
108         for ( i = 1; i < sizeof(ber_tag_t); i++ ) {
109                 if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 ) {
110                         return LBER_DEFAULT;
111                 }
112
113                 tag <<= 8;
114                 tag |= 0x00ffUL & (ber_tag_t) xbyte;
115
116                 if ( ! (xbyte & LBER_MORE_TAG_MASK) ) {
117                         break;
118                 }
119         }
120
121         /* tag too big! */
122         if ( i == sizeof(ber_tag_t) ) {
123                 return LBER_DEFAULT;
124         }
125
126         return tag;
127 }
128
129 ber_tag_t
130 ber_skip_tag( BerElement *ber, ber_len_t *len )
131 {
132         ber_tag_t       tag;
133         unsigned char   lc;
134         ber_len_t       i, noctets;
135         unsigned char netlen[sizeof(ber_len_t)];
136
137         assert( ber != NULL );
138         assert( len != NULL );
139         assert( LBER_VALID( ber ) );
140
141         /*
142          * Any ber element looks like this: tag length contents.
143          * Assuming everything's ok, we return the tag byte (we
144          * can assume a single byte), and return the length in len.
145          *
146          * Assumptions:
147          *      1) definite lengths
148          *      2) primitive encodings used whenever possible
149          */
150
151         *len = 0;
152
153         /*
154          * First, we read the tag.
155          */
156
157         if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT ) {
158                 return LBER_DEFAULT;
159         }
160
161         /*
162          * Next, read the length.  The first byte contains the length of
163          * the length.  If bit 8 is set, the length is the long form,
164          * otherwise it's the short form.  We don't allow a length that's
165          * greater than what we can hold in a ber_len_t.
166          */
167
168         if ( ber_read( ber, (char *) &lc, 1 ) != 1 ) {
169                 return LBER_DEFAULT;
170         }
171
172         if ( lc & 0x80U ) {
173                 noctets = (lc & 0x7fU);
174
175                 if ( noctets > sizeof(ber_len_t) ) {
176                         return LBER_DEFAULT;
177                 }
178
179                 if( (unsigned) ber_read( ber, (char *) netlen, noctets ) != noctets ) {
180                         return LBER_DEFAULT;
181                 }
182
183                 for( i = 0; i < noctets; i++ ) {
184                         *len <<= 8;
185                         *len |= netlen[i];
186                 }
187
188         } else {
189                 *len = lc;
190         }
191
192         /* BER element should have enough data left */
193         if( *len > (ber_len_t) ber_pvt_ber_remaining( ber ) ) {
194                 return LBER_DEFAULT;
195         }
196         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
197
198         return tag;
199 }
200
201 ber_tag_t
202 ber_peek_tag(
203         BerElement *ber,
204         ber_len_t *len )
205 {
206         /*
207          * This implementation assumes ber_skip_tag() only
208          * modifies ber_ptr field of the BerElement.
209          */
210
211         char *save;
212         ber_tag_t       tag, old;
213
214         old = ber->ber_tag;
215         save = ber->ber_ptr;
216         tag = ber_skip_tag( ber, len );
217         ber->ber_ptr = save;
218         ber->ber_tag = old;
219
220         return tag;
221 }
222
223 static ber_len_t
224 ber_getnint(
225         BerElement *ber,
226         ber_int_t *num,
227         ber_len_t len )
228 {
229         unsigned char buf[sizeof(ber_int_t)];
230
231         assert( ber != NULL );
232         assert( num != NULL );
233         assert( LBER_VALID( ber ) );
234
235         /*
236          * The tag and length have already been stripped off.  We should
237          * be sitting right before len bytes of 2's complement integer,
238          * ready to be read straight into an int.  We may have to sign
239          * extend after we read it in.
240          */
241
242         if ( len > sizeof(ber_int_t) ) {
243                 return -1;
244         }
245
246         /* read into the low-order bytes of our buffer */
247         if ( (ber_len_t) ber_read( ber, (char *) buf, len ) != len ) {
248                 return -1;
249         }
250
251         if( len ) {
252                 /* sign extend if necessary */
253                 ber_len_t i;
254                 ber_int_t netnum = 0x80 & buf[0] ? -1 : 0;
255
256                 /* shift in the bytes */
257                 for( i=0 ; i<len; i++ ) {
258                         netnum = (netnum << 8 ) | buf[i];
259                 }
260
261                 *num = netnum;
262
263         } else {
264                 *num = 0;
265         }
266         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
267
268         return len;
269 }
270
271 ber_tag_t
272 ber_get_int(
273         BerElement *ber,
274         ber_int_t *num )
275 {
276         ber_tag_t       tag;
277         ber_len_t       len;
278
279         assert( ber != NULL );
280         assert( LBER_VALID( ber ) );
281
282         if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
283                 return LBER_DEFAULT;
284         }
285
286         if ( ber_getnint( ber, num, len ) != len ) {
287                 return LBER_DEFAULT;
288         }
289         
290         return tag;
291 }
292
293 ber_tag_t
294 ber_get_enum(
295         BerElement *ber,
296         ber_int_t *num )
297 {
298         return ber_get_int( ber, num );
299 }
300
301 ber_tag_t
302 ber_get_stringb(
303         BerElement *ber,
304         char *buf,
305         ber_len_t *len )
306 {
307         ber_len_t       datalen;
308         ber_tag_t       tag;
309
310         assert( ber != NULL );
311         assert( LBER_VALID( ber ) );
312
313         if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) {
314                 return LBER_DEFAULT;
315         }
316
317         /* must fit within allocated space with termination */
318         if ( datalen >= *len ) {
319                 return LBER_DEFAULT;
320         }
321
322         if ( (ber_len_t) ber_read( ber, buf, datalen ) != datalen ) {
323                 return LBER_DEFAULT;
324         }
325         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
326
327         buf[datalen] = '\0';
328
329         *len = datalen;
330         return tag;
331 }
332
333 /* Definitions for get_string vector
334  *
335  * ChArray, BvArray, and BvVec are self-explanatory.
336  * BvOff is a struct berval embedded in an array of larger structures
337  * of siz bytes at off bytes from the beginning of the struct.
338  */
339 enum bgbvc { ChArray, BvArray, BvVec, BvOff };
340
341 /* Use this single cookie for state, to keep actual
342  * stack use to the absolute minimum.
343  */
344 typedef struct bgbvr {
345         enum bgbvc choice;
346         BerElement *ber;
347         int alloc;
348         ber_len_t siz;
349         ber_len_t off;
350         union {
351                 char ***c;
352                 BerVarray *ba;
353                 struct berval ***bv;
354         } res;
355 } bgbvr;
356
357 static ber_tag_t
358 ber_get_stringbvl( bgbvr *b, ber_len_t *rlen )
359 {
360         int i = 0, n;
361         ber_tag_t tag;
362         ber_len_t len;
363         char *last, *orig;
364         struct berval bv, *bvp = NULL;
365
366         /* For rewinding, just like ber_peek_tag() */
367         orig = b->ber->ber_ptr;
368         tag = b->ber->ber_tag;
369
370         if ( ber_first_element( b->ber, &len, &last ) != LBER_DEFAULT ) {
371                 for ( ; b->ber->ber_ptr < last; i++ ) {
372                         if (ber_skip_tag( b->ber, &len ) == LBER_DEFAULT) break;
373                         b->ber->ber_ptr += len;
374                         b->ber->ber_tag = *(unsigned char *)b->ber->ber_ptr;
375                 }
376         }
377
378         if ( rlen ) *rlen = i;
379
380         if ( i == 0 ) {
381                 *b->res.c = NULL;
382                 return 0;
383         }
384
385         n = i;
386
387         /* Allocate the result vector */
388         switch (b->choice) {
389         case ChArray:
390                 *b->res.c = ber_memalloc_x( (n+1)*sizeof( char * ),
391                         b->ber->ber_memctx);
392                 if ( *b->res.c == NULL ) return LBER_DEFAULT;
393                 (*b->res.c)[n] = NULL;
394                 break;
395         case BvArray:
396                 *b->res.ba = ber_memalloc_x( (n+1)*sizeof( struct berval ),
397                         b->ber->ber_memctx);
398                 if ( *b->res.ba == NULL ) return LBER_DEFAULT;
399                 (*b->res.ba)[n].bv_val = NULL;
400                 break;
401         case BvVec:
402                 *b->res.bv = ber_memalloc_x( (n+1)*sizeof( struct berval *),
403                         b->ber->ber_memctx);
404                 if ( *b->res.bv == NULL ) return LBER_DEFAULT;
405                 (*b->res.bv)[n] = NULL;
406                 break;
407         case BvOff:
408                 *b->res.ba = ber_memalloc_x( (n+1) * b->siz, b->ber->ber_memctx );
409                 if ( *b->res.ba == NULL ) return LBER_DEFAULT;
410                 ((struct berval *)((long)(*b->res.ba) + n*b->siz +
411                         b->off))->bv_val = NULL;
412                 break;
413         }
414         b->ber->ber_ptr = orig;
415         b->ber->ber_tag = tag;
416         ber_skip_tag( b->ber, &len );
417         
418         for (n=0; n<i; n++)
419         {
420                 tag = ber_next_element( b->ber, &len, last );
421                 if ( ber_get_stringbv( b->ber, &bv, b->alloc ) == LBER_DEFAULT ) {
422                         goto nomem;
423                 }
424
425                 /* store my result */
426                 switch (b->choice) {
427                 case ChArray:
428                         (*b->res.c)[n] = bv.bv_val;
429                         break;
430                 case BvArray:
431                         (*b->res.ba)[n] = bv;
432                         break;
433                 case BvVec:
434                         bvp = ber_memalloc_x( sizeof( struct berval ), b->ber->ber_memctx);
435                         if ( !bvp ) {
436                                 LBER_FREE(bv.bv_val);
437                                 goto nomem;
438                         }
439                         (*b->res.bv)[n] = bvp;
440                         *bvp = bv;
441                         break;
442                 case BvOff:
443                         *(BerVarray)((long)(*b->res.ba)+n*b->siz+b->off) = bv;
444                         break;
445                 }
446         }
447         return tag;
448
449 nomem:
450         if (b->alloc || b->choice == BvVec) {
451                 for (--n; n>=0; n--) {
452                         switch(b->choice) {
453                         case ChArray:
454                                 LBER_FREE((*b->res.c)[n]);
455                                 break;
456                         case BvArray:
457                                 LBER_FREE((*b->res.ba)[n].bv_val);
458                                 break;
459                         case BvVec:
460                                 LBER_FREE((*b->res.bv)[n]->bv_val);
461                                 LBER_FREE((*b->res.bv)[n]);
462                                 break;
463                         default:
464                                 break;
465                         }
466                 }
467         }
468         LBER_FREE(*b->res.c);
469         *b->res.c = NULL;
470         return LBER_DEFAULT;
471 }
472
473 ber_tag_t
474 ber_get_stringbv( BerElement *ber, struct berval *bv, int option )
475 {
476         ber_tag_t       tag;
477
478         assert( ber != NULL );
479         assert( bv != NULL );
480
481         assert( LBER_VALID( ber ) );
482
483         if ( (tag = ber_skip_tag( ber, &bv->bv_len )) == LBER_DEFAULT ) {
484                 bv->bv_val = NULL;
485                 return LBER_DEFAULT;
486         }
487
488         if ( (ber_len_t) ber_pvt_ber_remaining( ber ) < bv->bv_len ) {
489                 return LBER_DEFAULT;
490         }
491
492         if ( option & LBER_BV_ALLOC ) {
493                 bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
494                         ber->ber_memctx );
495                 if ( bv->bv_val == NULL ) {
496                         return LBER_DEFAULT;
497                 }
498
499                 if ( bv->bv_len > 0 && (ber_len_t) ber_read( ber, bv->bv_val,
500                         bv->bv_len ) != bv->bv_len )
501                 {
502                         LBER_FREE( bv->bv_val );
503                         bv->bv_val = NULL;
504                         return LBER_DEFAULT;
505                 }
506         } else {
507                 bv->bv_val = ber->ber_ptr;
508                 ber->ber_ptr += bv->bv_len;
509         }
510         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
511         if ( !( option & LBER_BV_NOTERM ))
512                 bv->bv_val[bv->bv_len] = '\0';
513
514         return tag;
515 }
516
517 ber_tag_t
518 ber_get_stringbv_null( BerElement *ber, struct berval *bv, int option )
519 {
520         ber_tag_t       tag;
521
522         assert( ber != NULL );
523         assert( bv != NULL );
524
525         assert( LBER_VALID( ber ) );
526
527         if ( (tag = ber_skip_tag( ber, &bv->bv_len )) == LBER_DEFAULT ) {
528                 bv->bv_val = NULL;
529                 return LBER_DEFAULT;
530         }
531
532         if ( (ber_len_t) ber_pvt_ber_remaining( ber ) < bv->bv_len ) {
533                 return LBER_DEFAULT;
534         }
535
536         if ( bv->bv_len == 0 ) {
537                 bv->bv_val = NULL;
538                 ber->ber_tag = *(unsigned char *)ber->ber_ptr;
539                 return tag;
540         }
541
542         if ( option & LBER_BV_ALLOC ) {
543                 bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
544                         ber->ber_memctx );
545                 if ( bv->bv_val == NULL ) {
546                         return LBER_DEFAULT;
547                 }
548
549                 if ( bv->bv_len > 0 && (ber_len_t) ber_read( ber, bv->bv_val,
550                         bv->bv_len ) != bv->bv_len )
551                 {
552                         LBER_FREE( bv->bv_val );
553                         bv->bv_val = NULL;
554                         return LBER_DEFAULT;
555                 }
556         } else {
557                 bv->bv_val = ber->ber_ptr;
558                 ber->ber_ptr += bv->bv_len;
559         }
560         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
561         if ( !( option & LBER_BV_NOTERM ))
562                 bv->bv_val[bv->bv_len] = '\0';
563
564         return tag;
565 }
566
567 ber_tag_t
568 ber_get_stringa( BerElement *ber, char **buf )
569 {
570         BerValue        bv;
571         ber_tag_t       tag;
572
573         assert( buf != NULL );
574
575         tag = ber_get_stringbv( ber, &bv, LBER_BV_ALLOC );
576         *buf = bv.bv_val;
577
578         return tag;
579 }
580
581 ber_tag_t
582 ber_get_stringa_null( BerElement *ber, char **buf )
583 {
584         BerValue        bv;
585         ber_tag_t       tag;
586
587         assert( buf != NULL );
588
589         tag = ber_get_stringbv_null( ber, &bv, LBER_BV_ALLOC );
590         *buf = bv.bv_val;
591
592         return tag;
593 }
594
595 ber_tag_t
596 ber_get_stringal( BerElement *ber, struct berval **bv )
597 {
598         ber_tag_t       tag;
599
600         assert( ber != NULL );
601         assert( bv != NULL );
602
603         *bv = (struct berval *) ber_memalloc_x( sizeof(struct berval),
604                 ber->ber_memctx );
605         if ( *bv == NULL ) {
606                 return LBER_DEFAULT;
607         }
608
609         tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC );
610         if ( tag == LBER_DEFAULT ) {
611                 LBER_FREE( *bv );
612                 *bv = NULL;
613         }
614         return tag;
615 }
616
617 ber_tag_t
618 ber_get_bitstringa(
619         BerElement *ber,
620         char **buf,
621         ber_len_t *blen )
622 {
623         ber_len_t       datalen;
624         ber_tag_t       tag;
625         unsigned char   unusedbits;
626
627         assert( ber != NULL );
628         assert( buf != NULL );
629         assert( blen != NULL );
630
631         assert( LBER_VALID( ber ) );
632
633         if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) {
634                 *buf = NULL;
635                 return LBER_DEFAULT;
636         }
637         --datalen;
638
639         *buf = (char *) ber_memalloc_x( datalen, ber->ber_memctx );
640         if ( *buf == NULL ) {
641                 return LBER_DEFAULT;
642         }
643
644         if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 ) {
645                 LBER_FREE( buf );
646                 *buf = NULL;
647                 return LBER_DEFAULT;
648         }
649
650         if ( (ber_len_t) ber_read( ber, *buf, datalen ) != datalen ) {
651                 LBER_FREE( buf );
652                 *buf = NULL;
653                 return LBER_DEFAULT;
654         }
655         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
656
657         *blen = datalen * 8 - unusedbits;
658         return tag;
659 }
660
661 ber_tag_t
662 ber_get_null( BerElement *ber )
663 {
664         ber_len_t       len;
665         ber_tag_t       tag;
666
667         assert( ber != NULL );
668         assert( LBER_VALID( ber ) );
669
670         if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
671                 return LBER_DEFAULT;
672         }
673
674         if ( len != 0 ) {
675                 return LBER_DEFAULT;
676         }
677         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
678
679         return( tag );
680 }
681
682 ber_tag_t
683 ber_get_boolean(
684         BerElement *ber,
685         ber_int_t *boolval )
686 {
687         ber_int_t       longbool;
688         ber_tag_t       rc;
689
690         assert( ber != NULL );
691         assert( boolval != NULL );
692
693         assert( LBER_VALID( ber ) );
694
695         rc = ber_get_int( ber, &longbool );
696         *boolval = longbool;
697
698         return rc;
699 }
700
701 ber_tag_t
702 ber_first_element(
703         BerElement *ber,
704         ber_len_t *len,
705         char **last )
706 {
707         assert( ber != NULL );
708         assert( len != NULL );
709         assert( last != NULL );
710
711         /* skip the sequence header, use the len to mark where to stop */
712         if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
713                 *last = NULL;
714                 return LBER_DEFAULT;
715         }
716         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
717
718         *last = ber->ber_ptr + *len;
719
720         if ( *last == ber->ber_ptr ) {
721                 return LBER_DEFAULT;
722         }
723
724         return ber_peek_tag( ber, len );
725 }
726
727 ber_tag_t
728 ber_next_element(
729         BerElement *ber,
730         ber_len_t *len,
731         LDAP_CONST char *last )
732 {
733         assert( ber != NULL );
734         assert( len != NULL );
735         assert( last != NULL );
736
737         assert( LBER_VALID( ber ) );
738
739         if ( ber->ber_ptr >= last ) {
740                 return LBER_DEFAULT;
741         }
742
743         return ber_peek_tag( ber, len );
744 }
745
746 /* VARARGS */
747 ber_tag_t
748 ber_scanf ( BerElement *ber,
749         LDAP_CONST char *fmt,
750         ... )
751 {
752         va_list         ap;
753         LDAP_CONST char         *fmt_reset;
754         char            *s, **ss;
755         struct berval   **bvp, *bval;
756         ber_int_t       *i;
757         ber_len_t       *l;
758         ber_tag_t       *t;
759         ber_tag_t       rc;
760         ber_len_t       len;
761
762         va_start( ap, fmt );
763
764         assert( ber != NULL );
765         assert( fmt != NULL );
766
767         assert( LBER_VALID( ber ) );
768
769         fmt_reset = fmt;
770
771         ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
772                 "ber_scanf fmt (%s) ber:\n", fmt );
773         ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
774
775         for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) {
776                 /* When this is modified, remember to update
777                  * the error-cleanup code below accordingly. */
778                 switch ( *fmt ) {
779                 case '!': { /* Hook */
780                                 BERDecodeCallback *f;
781                                 void *p;
782
783                                 f = va_arg( ap, BERDecodeCallback * );
784                                 p = va_arg( ap, void * );
785
786                                 rc = (*f)( ber, p, 0 );
787                         } break;
788
789                 case 'a':       /* octet string - allocate storage as needed */
790                         ss = va_arg( ap, char ** );
791                         rc = ber_get_stringa( ber, ss );
792                         break;
793
794                 case 'A':       /* octet string - allocate storage as needed,
795                                  * but return NULL if len == 0 */
796                         ss = va_arg( ap, char ** );
797                         rc = ber_get_stringa_null( ber, ss );
798                         break;
799
800                 case 'b':       /* boolean */
801                         i = va_arg( ap, ber_int_t * );
802                         rc = ber_get_boolean( ber, i );
803                         break;
804
805                 case 'B':       /* bit string - allocate storage as needed */
806                         ss = va_arg( ap, char ** );
807                         l = va_arg( ap, ber_len_t * ); /* for length, in bits */
808                         rc = ber_get_bitstringa( ber, ss, l );
809                         break;
810
811                 case 'e':       /* enumerated */
812                 case 'i':       /* int */
813                         i = va_arg( ap, ber_int_t * );
814                         rc = ber_get_int( ber, i );
815                         break;
816
817                 case 'l':       /* length of next item */
818                         l = va_arg( ap, ber_len_t * );
819                         rc = ber_peek_tag( ber, l );
820                         break;
821
822                 case 'm':       /* octet string in berval, in-place */
823                         bval = va_arg( ap, struct berval * );
824                         rc = ber_get_stringbv( ber, bval, 0 );
825                         break;
826
827                 case 'M':       /* bvoffarray - must include address of
828                                  * a record len, and record offset.
829                                  * number of records will be returned thru
830                                  * len ptr on finish. parsed in-place.
831                                  */
832                 {
833                         bgbvr cookie = { BvOff };
834                         cookie.ber = ber;
835                         cookie.res.ba = va_arg( ap, struct berval ** );
836                         cookie.alloc = 0;
837                         l = va_arg( ap, ber_len_t * );
838                         cookie.siz = *l;
839                         cookie.off = va_arg( ap, ber_len_t );
840                         rc = ber_get_stringbvl( &cookie, l );
841                         break;
842                 }
843
844                 case 'n':       /* null */
845                         rc = ber_get_null( ber );
846                         break;
847
848                 case 'o':       /* octet string in a supplied berval */
849                         bval = va_arg( ap, struct berval * );
850                         rc = ber_get_stringbv( ber, bval, LBER_BV_ALLOC );
851                         break;
852
853                 case 'O':       /* octet string - allocate & include length */
854                         bvp = va_arg( ap, struct berval ** );
855                         rc = ber_get_stringal( ber, bvp );
856                         break;
857
858                 case 's':       /* octet string - in a buffer */
859                         s = va_arg( ap, char * );
860                         l = va_arg( ap, ber_len_t * );
861                         rc = ber_get_stringb( ber, s, l );
862                         break;
863
864                 case 't':       /* tag of next item */
865                         t = va_arg( ap, ber_tag_t * );
866                         *t = rc = ber_peek_tag( ber, &len );
867                         break;
868
869                 case 'T':       /* skip tag of next item */
870                         t = va_arg( ap, ber_tag_t * );
871                         *t = rc = ber_skip_tag( ber, &len );
872                         break;
873
874                 case 'v':       /* sequence of strings */
875                 {
876                         bgbvr cookie = { ChArray };
877                         cookie.ber = ber;
878                         cookie.res.c = va_arg( ap, char *** );
879                         cookie.alloc = LBER_BV_ALLOC;
880                         rc = ber_get_stringbvl( &cookie, NULL );
881                         break;
882                 }
883
884                 case 'V':       /* sequence of strings + lengths */
885                 {
886                         bgbvr cookie = { BvVec };
887                         cookie.ber = ber;
888                         cookie.res.bv = va_arg( ap, struct berval *** );
889                         cookie.alloc = LBER_BV_ALLOC;
890                         rc = ber_get_stringbvl( &cookie, NULL );
891                         break;
892                 }
893
894                 case 'W':       /* bvarray */
895                 {
896                         bgbvr cookie = { BvArray };
897                         cookie.ber = ber;
898                         cookie.res.ba = va_arg( ap, struct berval ** );
899                         cookie.alloc = LBER_BV_ALLOC;
900                         rc = ber_get_stringbvl( &cookie, NULL );
901                         break;
902                 }
903
904                 case 'x':       /* skip the next element - whatever it is */
905                         if ( (rc = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
906                                 break;
907                         ber->ber_ptr += len;
908                         ber->ber_tag = *(unsigned char *)ber->ber_ptr;
909                         break;
910
911                 case '{':       /* begin sequence */
912                 case '[':       /* begin set */
913                         if ( *(fmt + 1) != 'v' && *(fmt + 1) != 'V'
914                                 && *(fmt + 1) != 'W' && *(fmt + 1) != 'M' )
915                                 rc = ber_skip_tag( ber, &len );
916                         break;
917
918                 case '}':       /* end sequence */
919                 case ']':       /* end set */
920                         break;
921
922                 default:
923                         if( ber->ber_debug ) {
924                                 ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
925                                         "ber_scanf: unknown fmt %c\n", *fmt );
926                         }
927                         rc = LBER_DEFAULT;
928                         break;
929                 }
930         }
931
932         va_end( ap );
933         if ( rc == LBER_DEFAULT ) {
934                 /*
935                  * Error.  Reclaim malloced memory that was given to the caller.
936                  * Set allocated pointers to NULL, "data length" outvalues to 0.
937                  */
938                 va_start( ap, fmt );
939
940                 for ( ; fmt_reset < fmt; fmt_reset++ ) {
941                 switch ( *fmt_reset ) {
942                 case '!': { /* Hook */
943                                 BERDecodeCallback *f;
944                                 void *p;
945
946                                 f = va_arg( ap, BERDecodeCallback * );
947                                 p = va_arg( ap, void * );
948
949                                 (void) (*f)( ber, p, 1 );
950                         } break;
951
952                 case 'a':       /* octet string - allocate storage as needed */
953                 case 'A':
954                         ss = va_arg( ap, char ** );
955                         if ( *ss ) {
956                                 LBER_FREE( *ss );
957                                 *ss = NULL;
958                         }
959                         break;
960
961                 case 'b':       /* boolean */
962                 case 'e':       /* enumerated */
963                 case 'i':       /* int */
964                         (void) va_arg( ap, int * );
965                         break;
966
967                 case 'l':       /* length of next item */
968                         (void) va_arg( ap, ber_len_t * );
969                         break;
970
971                 case 'o':       /* octet string in a supplied berval */
972                         bval = va_arg( ap, struct berval * );
973                         if ( bval->bv_val != NULL ) {
974                                 LBER_FREE( bval->bv_val );
975                                 bval->bv_val = NULL;
976                         }
977                         bval->bv_len = 0;
978                         break;
979
980                 case 'O':       /* octet string - allocate & include length */
981                         bvp = va_arg( ap, struct berval ** );
982                         if ( *bvp ) {
983                                 ber_bvfree( *bvp );
984                                 *bvp = NULL;
985                         }
986                         break;
987
988                 case 's':       /* octet string - in a buffer */
989                         (void) va_arg( ap, char * );
990                         (void) va_arg( ap, ber_len_t * );
991                         break;
992
993                 case 't':       /* tag of next item */
994                 case 'T':       /* skip tag of next item */
995                         (void) va_arg( ap, ber_tag_t * );
996                         break;
997
998                 case 'B':       /* bit string - allocate storage as needed */
999                         ss = va_arg( ap, char ** );
1000                         if ( *ss ) {
1001                                 LBER_FREE( *ss );
1002                                 *ss = NULL;
1003                         }
1004                         *(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */
1005                         break;
1006
1007                 case 'm':       /* berval in-place */
1008                 case 'M':       /* BVoff array in-place */
1009                 case 'n':       /* null */
1010                 case 'v':       /* sequence of strings */
1011                 case 'V':       /* sequence of strings + lengths */
1012                 case 'W':       /* BerVarray */
1013                 case 'x':       /* skip the next element - whatever it is */
1014                 case '{':       /* begin sequence */
1015                 case '[':       /* begin set */
1016                 case '}':       /* end sequence */
1017                 case ']':       /* end set */
1018                         break;
1019
1020                 default:
1021                         /* format should be good */
1022                         assert( 0 );
1023                 }
1024                 }
1025
1026                 va_end( ap );
1027         }
1028
1029         return rc;
1030 }