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