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