xref: /illumos-gate/usr/src/lib/libkmf/ber_der/common/decode.c (revision 168c213023b7f347f11abfc72f448b0c621ab718)
1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /*
6  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
7  *
8  * The contents of this file are subject to the Netscape Public License
9  * Version 1.0 (the "NPL"); you may not use this file except in
10  * compliance with the NPL.  You may obtain a copy of the NPL at
11  * http://www.mozilla.org/NPL/
12  *
13  * Software distributed under the NPL is distributed on an "AS IS" basis,
14  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
15  * for the specific language governing rights and limitations under the
16  * NPL.
17  *
18  * The Initial Developer of this code under the NPL is Netscape
19  * Communications Corporation.  Portions created by Netscape are
20  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
21  * Reserved.
22  */
23 
24 /*
25  * Copyright (c) 1990 Regents of the University of Michigan.
26  * All rights reserved.
27  *
28  * Redistribution and use in source and binary forms are permitted
29  * provided that this notice is preserved and that due credit is given
30  * to the University of Michigan at Ann Arbor. The name of the University
31  * may not be used to endorse or promote products derived from this
32  * software without specific prior written permission. This software
33  * is provided ``as is'' without express or implied warranty.
34  */
35 
36 /* decode.c - ber input decoding routines */
37 
38 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 #include <strings.h>
41 #include <sys/types.h>
42 #include <netinet/in.h>
43 #include <inttypes.h>
44 
45 #include <ber_der.h>
46 #include "kmfber_int.h"
47 
48 static void
49 ber_svecfree(char **vals)
50 {
51 	int	i;
52 
53 	if (vals == NULL)
54 		return;
55 	for (i = 0; vals[i] != NULL; i++)
56 		free(vals[i]);
57 	free((char *)vals);
58 }
59 
60 /*
61  * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
62  * If that changes, the kmfber_peek_tag() and/or
63  * kmfkmfber_skip_tag() implementations will need to be changed.
64  */
65 /* return the tag - KMFBER_DEFAULT returned means trouble */
66 static ber_tag_t
67 kmfber_get_tag(BerElement *ber)
68 {
69 	unsigned char	xbyte;
70 	ber_tag_t	tag;
71 	char		*tagp;
72 	int		i;
73 
74 	if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
75 		return (KMFBER_DEFAULT);
76 
77 	if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
78 		return ((ber_uint_t)xbyte);
79 
80 	tagp = (char *)&tag;
81 	tagp[0] = xbyte;
82 	for (i = 1; i < sizeof (ber_int_t); i++) {
83 		if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
84 			return (KMFBER_DEFAULT);
85 
86 		tagp[i] = xbyte;
87 
88 		if (! (xbyte & KMFBER_MORE_TAG_MASK))
89 			break;
90 	}
91 
92 	/* tag too big! */
93 	if (i == sizeof (ber_int_t))
94 		return (KMFBER_DEFAULT);
95 
96 	/* want leading, not trailing 0's */
97 	return (tag >> (sizeof (ber_int_t)- i - 1));
98 }
99 
100 /*
101  * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
102  * If that changes, the implementation of kmfber_peek_tag() will need to
103  * be changed.
104  */
105 ber_tag_t
106 kmfber_skip_tag(BerElement *ber, ber_len_t *len)
107 {
108 	ber_tag_t	tag;
109 	unsigned char	lc;
110 	int		noctets, diff;
111 	uint32_t	netlen;
112 
113 	/*
114 	 * Any ber element looks like this: tag length contents.
115 	 * Assuming everything's ok, we return the tag byte (we
116 	 * can assume a single byte), and return the length in len.
117 	 *
118 	 * Assumptions:
119 	 *	1) definite lengths
120 	 *	2) primitive encodings used whenever possible
121 	 */
122 
123 	/*
124 	 * First, we read the tag.
125 	 */
126 
127 	if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
128 		return (KMFBER_DEFAULT);
129 
130 	/*
131 	 * Next, read the length.  The first byte contains the length of
132 	 * the length.  If bit 8 is set, the length is the long form,
133 	 * otherwise it's the short form.  We don't allow a length that's
134 	 * greater than what we can hold in an unsigned long.
135 	 */
136 
137 	*len = 0;
138 	netlen = 0;
139 	if (kmfber_read(ber, (char *)&lc, 1) != 1)
140 		return (KMFBER_DEFAULT);
141 	if (lc & 0x80) {
142 		noctets = (lc & 0x7f);
143 		if (noctets > sizeof (ber_uint_t))
144 			return (KMFBER_DEFAULT);
145 		diff = sizeof (ber_int_t) - noctets;
146 		if (kmfber_read(ber, (char *)&netlen + diff, noctets)
147 			!= noctets)
148 			return (KMFBER_DEFAULT);
149 		*len = ntohl(netlen);
150 	} else {
151 		*len = lc;
152 	}
153 
154 	return (tag);
155 }
156 
157 
158 /*
159  * Note: Previously, we passed the "ber" parameter directly to
160  * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
161  * We now take advantage of the fact that the only ber structure
162  * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
163  * If that changes, this code must change too.
164  */
165 static ber_tag_t
166 kmfber_peek_tag(BerElement *ber, ber_len_t *len)
167 {
168 	BerElement	bercopy;
169 
170 	bercopy.ber_end = ber->ber_end;
171 	bercopy.ber_ptr = ber->ber_ptr;
172 	return (kmfber_skip_tag(&bercopy, len));
173 }
174 
175 static int
176 ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
177 {
178 	int i;
179 	ber_int_t value;
180 	unsigned char buffer[sizeof (ber_int_t)];
181 	/*
182 	 * The tag and length have already been stripped off.  We should
183 	 * be sitting right before len bytes of 2's complement integer,
184 	 * ready to be read straight into an int.  We may have to sign
185 	 * extend after we read it in.
186 	 */
187 
188 	if (len > sizeof (ber_slen_t))
189 		return (-1);
190 
191 	/* read into the low-order bytes of netnum */
192 	if (kmfber_read(ber, (char *)buffer, len) != len)
193 		return (-1);
194 
195 	/* This sets the required sign extension */
196 	if (len != 0) {
197 		value = 0x80 & buffer[0] ? (-1) : 0;
198 	} else {
199 		value = 0;
200 	}
201 
202 	for (i = 0; i < len; i++)
203 		value = (value << 8) | buffer[i];
204 
205 	*num = value;
206 
207 	return (len);
208 }
209 
210 static ber_tag_t
211 kmfber_get_int(BerElement *ber, ber_int_t *num)
212 {
213 	ber_tag_t	tag;
214 	ber_len_t	len;
215 
216 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
217 		return (KMFBER_DEFAULT);
218 
219 	/*
220 	 * len is being demoted to a long here --  possible conversion error
221 	 */
222 
223 	if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
224 		return (KMFBER_DEFAULT);
225 	else
226 		return (tag);
227 }
228 
229 static ber_tag_t
230 kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
231 {
232 	ber_len_t	datalen;
233 	ber_tag_t	tag;
234 #ifdef STR_TRANSLATION
235 	char		*transbuf;
236 #endif /* STR_TRANSLATION */
237 
238 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
239 		return (KMFBER_DEFAULT);
240 	if (datalen > (*len - 1))
241 		return (KMFBER_DEFAULT);
242 
243 	/*
244 	 * datalen is being demoted to a long here --  possible conversion error
245 	 */
246 
247 	if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
248 		return (KMFBER_DEFAULT);
249 
250 	buf[datalen] = '\0';
251 
252 #ifdef STR_TRANSLATION
253 	if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
254 		!= 0 && ber->ber_decode_translate_proc != NULL) {
255 
256 		transbuf = buf;
257 		++datalen;
258 		if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
259 			0) != 0) {
260 			return (KMFBER_DEFAULT);
261 		}
262 		if (datalen > *len) {
263 			free(transbuf);
264 			return (KMFBER_DEFAULT);
265 		}
266 		(void) memmove(buf, transbuf, datalen);
267 		free(transbuf);
268 		--datalen;
269 	}
270 #endif /* STR_TRANSLATION */
271 
272 	*len = datalen;
273 	return (tag);
274 }
275 
276 static ber_tag_t
277 kmfber_get_stringa(BerElement *ber, char **buf)
278 {
279 	ber_len_t	datalen;
280 	ber_tag_t	tag;
281 
282 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
283 		return (KMFBER_DEFAULT);
284 
285 	if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
286 		return (KMFBER_DEFAULT);
287 
288 	/*
289 	 * datalen is being demoted to a long here --  possible conversion error
290 	 */
291 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
292 		return (KMFBER_DEFAULT);
293 	(*buf)[datalen] = '\0';
294 
295 	return (tag);
296 }
297 
298 ber_tag_t
299 ber_get_oid(BerElement *ber, struct berval *oid)
300 {
301 	ber_len_t	len;
302 	ber_tag_t	tag;
303 
304 	if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
305 		return (KMFBER_DEFAULT);
306 	}
307 
308 	if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
309 		return (KMFBER_DEFAULT);
310 	}
311 	oid->bv_len = len;
312 
313 	if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
314 		(ber_slen_t)oid->bv_len)
315 		return (KMFBER_DEFAULT);
316 
317 	return (tag);
318 }
319 
320 ber_tag_t
321 ber_get_bigint(BerElement *ber, struct berval **bv)
322 {
323 	ber_len_t	len;
324 	ber_tag_t	tag;
325 
326 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
327 		== NULL) {
328 		return (KMFBER_DEFAULT);
329 	}
330 
331 	if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
332 		return (KMFBER_DEFAULT);
333 	}
334 
335 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
336 		== NULL) {
337 		return (KMFBER_DEFAULT);
338 	}
339 
340 	/*
341 	 * len is being demoted to a long here --  possible conversion error
342 	 */
343 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
344 		return (KMFBER_DEFAULT);
345 
346 	(*bv)->bv_len = len;
347 
348 	/* If DER encoding, strip leading 0's */
349 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
350 		char *p = (*bv)->bv_val;
351 		while ((*p == 0x00) && ((*bv)->bv_len > 0)) {
352 			p++;
353 			(*bv)->bv_len--;
354 		}
355 		/*
356 		 * Shift the buffer to the beginning of the allocated space
357 		 * so it can be properly freed later.
358 		 */
359 		if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
360 			(void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
361 	}
362 
363 	return (tag);
364 }
365 
366 static ber_tag_t
367 kmfber_get_stringal(BerElement *ber, struct berval **bv)
368 {
369 	ber_len_t	len;
370 	ber_tag_t	tag;
371 
372 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
373 		== NULL) {
374 		return (KMFBER_DEFAULT);
375 	}
376 
377 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
378 		return (KMFBER_DEFAULT);
379 	}
380 
381 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
382 		== NULL) {
383 		return (KMFBER_DEFAULT);
384 	}
385 
386 	/*
387 	 * len is being demoted to a long here --  possible conversion error
388 	 */
389 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
390 		return (KMFBER_DEFAULT);
391 	((*bv)->bv_val)[len] = '\0';
392 	(*bv)->bv_len = len;
393 
394 	return (tag);
395 }
396 
397 static ber_tag_t
398 kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
399 {
400 	ber_len_t	datalen;
401 	ber_tag_t	tag;
402 	unsigned char	unusedbits;
403 
404 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
405 		return (KMFBER_DEFAULT);
406 
407 	if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
408 		return (KMFBER_DEFAULT);
409 
410 	if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
411 		return (KMFBER_DEFAULT);
412 
413 	/* Subtract 1 for the unused bits */
414 	datalen--;
415 
416 	/*
417 	 * datalen is being demoted to a long here --  possible conversion error
418 	 */
419 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
420 		return (KMFBER_DEFAULT);
421 
422 	*blen = datalen * 8 - unusedbits;
423 	return (tag);
424 }
425 
426 static ber_tag_t
427 kmfber_get_null(BerElement *ber)
428 {
429 	ber_len_t	len;
430 	ber_tag_t tag;
431 
432 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
433 		return (KMFBER_DEFAULT);
434 
435 	if (len != 0)
436 		return (KMFBER_DEFAULT);
437 
438 	return (tag);
439 }
440 
441 static ber_tag_t
442 kmfber_get_boolean(BerElement *ber, int *boolval)
443 {
444 	ber_int_t	longbool;
445 	int		rc;
446 
447 	rc = kmfber_get_int(ber, &longbool);
448 	*boolval = longbool;
449 
450 	return (rc);
451 }
452 
453 ber_tag_t
454 kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
455 {
456 	/* skip the sequence header, use the len to mark where to stop */
457 	if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
458 		return (KMFBER_ERROR);
459 	}
460 
461 	*last = ber->ber_ptr + *len;
462 
463 	if (*last == ber->ber_ptr) {
464 		return (KMFBER_END_OF_SEQORSET);
465 	}
466 
467 	return (kmfber_peek_tag(ber, len));
468 }
469 
470 ber_tag_t
471 kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
472 {
473 	if (ber->ber_ptr == last) {
474 		return (KMFBER_END_OF_SEQORSET);
475 	}
476 
477 	return (kmfber_peek_tag(ber, len));
478 }
479 
480 void
481 kmfber_bvfree(struct berval *bv)
482 {
483 	if (bv != NULL) {
484 		if (bv->bv_val != NULL) {
485 			free(bv->bv_val);
486 		}
487 		free((char *)bv);
488 	}
489 }
490 
491 void
492 kmfber_bvecfree(struct berval **bv)
493 {
494 	int	i;
495 
496 	if (bv != NULL) {
497 		for (i = 0; bv[i] != NULL; i++) {
498 			kmfber_bvfree(bv[i]);
499 		}
500 		free((char *)bv);
501 	}
502 }
503 
504 /* VARARGS */
505 ber_tag_t
506 kmfber_scanf(BerElement *ber, const char *fmt, ...)
507 {
508 	va_list		ap;
509 	char		*last, *p;
510 	char		*s, **ss, ***sss;
511 	struct berval 	***bv, **bvp, *bval;
512 	int		*i, j;
513 	ber_slen_t	*l;
514 	ber_int_t	rc, tag, *b_int;
515 	ber_tag_t	*t;
516 	ber_len_t	len;
517 	size_t		array_size;
518 
519 	va_start(ap, fmt);
520 
521 	for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
522 	switch (*p) {
523 	    case 'a':	/* octet string - allocate storage as needed */
524 		ss = va_arg(ap, char **);
525 		rc = kmfber_get_stringa(ber, ss);
526 		break;
527 
528 	    case 'b':	/* boolean */
529 		i = va_arg(ap, int *);
530 		rc = kmfber_get_boolean(ber, i);
531 		break;
532 
533 	    case 'D':	/* Object ID */
534 		bval = va_arg(ap, struct berval *);
535 		rc = ber_get_oid(ber, bval);
536 		break;
537 	    case 'e':	/* enumerated */
538 	    case 'i':	/* int */
539 		b_int = va_arg(ap, ber_int_t *);
540 		rc = kmfber_get_int(ber, b_int);
541 		break;
542 
543 	    case 'l':	/* length of next item */
544 		l = va_arg(ap, ber_slen_t *);
545 		rc = kmfber_peek_tag(ber, (ber_len_t *)l);
546 		break;
547 
548 	    case 'n':	/* null */
549 		rc = kmfber_get_null(ber);
550 		break;
551 
552 	    case 's':	/* octet string - in a buffer */
553 		s = va_arg(ap, char *);
554 		l = va_arg(ap, ber_slen_t *);
555 		rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
556 		break;
557 
558 	    case 'o':	/* octet string in a supplied berval */
559 		bval = va_arg(ap, struct berval *);
560 		(void) kmfber_peek_tag(ber, &bval->bv_len);
561 		rc = kmfber_get_stringa(ber, &bval->bv_val);
562 		break;
563 
564 	    case 'I': /* variable length Integer */
565 		/* Treat INTEGER same as an OCTET string, but ignore the tag */
566 		bvp = va_arg(ap, struct berval **);
567 		rc = ber_get_bigint(ber, bvp);
568 		break;
569 	    case 'O': /* octet string - allocate & include length */
570 		bvp = va_arg(ap, struct berval **);
571 		rc = kmfber_get_stringal(ber, bvp);
572 		break;
573 
574 	    case 'B':	/* bit string - allocate storage as needed */
575 		ss = va_arg(ap, char **);
576 		l = va_arg(ap, ber_slen_t *); /* for length, in bits */
577 		rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
578 		break;
579 
580 	    case 't':	/* tag of next item */
581 		t = va_arg(ap, ber_tag_t *);
582 		*t = kmfber_peek_tag(ber, &len);
583 		rc = (ber_int_t)(*t);
584 		break;
585 
586 	    case 'T':	/* skip tag of next item */
587 		t = va_arg(ap, ber_tag_t *);
588 		*t = kmfber_skip_tag(ber, &len);
589 		rc = (ber_int_t)(*t);
590 		break;
591 
592 	    case 'v':	/* sequence of strings */
593 		sss = va_arg(ap, char ***);
594 		*sss = NULL;
595 		j = 0;
596 		array_size = 0;
597 		for (tag = kmfber_first_element(ber, &len, &last);
598 			(tag != KMFBER_DEFAULT &&
599 			tag != KMFBER_END_OF_SEQORSET &&
600 			rc != KMFBER_DEFAULT);
601 			tag = kmfber_next_element(ber, &len, last)) {
602 		    if (*sss == NULL) {
603 			/* Make room for at least 15 strings */
604 			*sss = (char **)malloc(16 * sizeof (char *));
605 			array_size = 16;
606 		    } else {
607 			if ((size_t)(j+2) > array_size) {
608 			    /* We'v overflowed our buffer */
609 			    *sss = (char **)realloc(*sss,
610 				(array_size * 2) * sizeof (char *));
611 			    array_size = array_size * 2;
612 			}
613 		    }
614 		    rc = kmfber_get_stringa(ber, &((*sss)[j]));
615 		    j++;
616 		}
617 		if (rc != KMFBER_DEFAULT &&
618 			tag != KMFBER_END_OF_SEQORSET) {
619 		    rc = KMFBER_DEFAULT;
620 		}
621 		if (j > 0)
622 		    (*sss)[j] = NULL;
623 		break;
624 
625 	    case 'V':	/* sequence of strings + lengths */
626 		bv = va_arg(ap, struct berval ***);
627 		*bv = NULL;
628 		j = 0;
629 		for (tag = kmfber_first_element(ber, &len, &last);
630 			(tag != KMFBER_DEFAULT &&
631 			tag != KMFBER_END_OF_SEQORSET &&
632 			rc != KMFBER_DEFAULT);
633 			tag = kmfber_next_element(ber, &len, last)) {
634 		    if (*bv == NULL) {
635 			*bv = (struct berval **)malloc(
636 				2 * sizeof (struct berval *));
637 		    } else {
638 			*bv = (struct berval **)realloc(*bv,
639 				(j + 2) * sizeof (struct berval *));
640 		    }
641 		    rc = kmfber_get_stringal(ber, &((*bv)[j]));
642 		    j++;
643 		}
644 		if (rc != KMFBER_DEFAULT &&
645 			tag != KMFBER_END_OF_SEQORSET) {
646 		    rc = KMFBER_DEFAULT;
647 		}
648 		if (j > 0)
649 		    (*bv)[j] = NULL;
650 		break;
651 
652 	    case 'x':	/* skip the next element - whatever it is */
653 		if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
654 		    break;
655 		ber->ber_ptr += len;
656 		break;
657 
658 	    case '{':	/* begin sequence */
659 	    case '[':	/* begin set */
660 		if (*(p + 1) != 'v' && *(p + 1) != 'V')
661 		    rc = kmfber_skip_tag(ber, &len);
662 		break;
663 
664 	    case '}':	/* end sequence */
665 	    case ']':	/* end set */
666 		break;
667 
668 	    default:
669 #ifdef KMFBER_DEBUG
670 		{
671 		    char msg[80];
672 		    sprintf(msg, "unknown fmt %c\n", *p);
673 		    ber_err_print(msg);
674 		}
675 #endif
676 		rc = KMFBER_DEFAULT;
677 		break;
678 	}
679 	}
680 
681 
682 	va_end(ap);
683 	if (rc == KMFBER_DEFAULT) {
684 	va_start(ap, fmt);
685 	for (p--; fmt < p && *fmt; fmt++) {
686 	    switch (*fmt) {
687 		case 'a':	/* octet string - allocate storage as needed */
688 		    ss = va_arg(ap, char **);
689 		    free(*ss);
690 		    *ss = NULL;
691 		    break;
692 
693 		case 'b':	/* boolean */
694 		    i = va_arg(ap, int *);
695 		    break;
696 
697 		case 'e':	/* enumerated */
698 		case 'i':	/* int */
699 		    l = va_arg(ap, ber_slen_t *);
700 		    break;
701 
702 		case 'l':	/* length of next item */
703 		    l = va_arg(ap, ber_slen_t *);
704 		    break;
705 
706 		case 'n':	/* null */
707 		    break;
708 
709 		case 's':	/* octet string - in a buffer */
710 		    s = va_arg(ap, char *);
711 		    l = va_arg(ap, ber_slen_t *);
712 		    break;
713 
714 		case 'o':	/* octet string in a supplied berval */
715 		    bval = va_arg(ap, struct berval *);
716 		    if (bval->bv_val) free(bval->bv_val);
717 		    (void) memset(bval, 0, sizeof (struct berval));
718 		    break;
719 
720 		case 'O':	/* octet string - allocate & include length */
721 		    bvp = va_arg(ap, struct berval **);
722 		    kmfber_bvfree(*bvp);
723 		    bvp = NULL;
724 		    break;
725 
726 		case 'B':	/* bit string - allocate storage as needed */
727 		    ss = va_arg(ap, char **);
728 		    l = va_arg(ap, ber_slen_t *); /* for length, in bits */
729 		    if (*ss) free(*ss);
730 		    *ss = NULL;
731 		    break;
732 
733 		case 't':	/* tag of next item */
734 		    t = va_arg(ap, ber_tag_t *);
735 		    break;
736 		case 'T':	/* skip tag of next item */
737 		    t = va_arg(ap, ber_tag_t *);
738 		    break;
739 
740 		case 'v':	/* sequence of strings */
741 		    sss = va_arg(ap, char ***);
742 		    ber_svecfree(*sss);
743 		    *sss = NULL;
744 		    break;
745 
746 		case 'V':	/* sequence of strings + lengths */
747 		    bv = va_arg(ap, struct berval ***);
748 		    kmfber_bvecfree(*bv);
749 		    *bv = NULL;
750 		    break;
751 
752 		case 'x':	/* skip the next element - whatever it is */
753 		    break;
754 
755 		case '{':	/* begin sequence */
756 		case '[':	/* begin set */
757 		    break;
758 
759 		case '}':	/* end sequence */
760 		case ']':	/* end set */
761 		    break;
762 
763 		default:
764 		    break;
765 	    }
766 	} /* for */
767 	va_end(ap);
768 	} /* if */
769 
770 
771 	return (rc);
772 }
773 
774 struct berval *
775 kmfber_bvdup(const struct berval *bv)
776 {
777 	struct berval	*new;
778 
779 	if ((new = (struct berval *)malloc(sizeof (struct berval)))
780 		== NULL) {
781 		return (NULL);
782 	}
783 	if (bv->bv_val == NULL) {
784 		new->bv_val = NULL;
785 		new->bv_len = 0;
786 	} else {
787 		if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
788 			== NULL) {
789 		    return (NULL);
790 		}
791 		(void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
792 		new->bv_val[bv->bv_len] = '\0';
793 		new->bv_len = bv->bv_len;
794 	}
795 
796 	return (new);
797 }
798