Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright 2009 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 #include <strings.h>
     39 #include <sys/types.h>
     40 #include <netinet/in.h>
     41 #include <inttypes.h>
     42 
     43 #include <ber_der.h>
     44 #include "kmfber_int.h"
     45 
     46 static void
     47 ber_svecfree(char **vals)
     48 {
     49 	int	i;
     50 
     51 	if (vals == NULL)
     52 		return;
     53 	for (i = 0; vals[i] != NULL; i++)
     54 		free(vals[i]);
     55 	free((char *)vals);
     56 }
     57 
     58 /*
     59  * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
     60  * If that changes, the kmfber_peek_tag() and/or
     61  * kmfkmfber_skip_tag() implementations will need to be changed.
     62  */
     63 /* return the tag - KMFBER_DEFAULT returned means trouble */
     64 static ber_tag_t
     65 kmfber_get_tag(BerElement *ber)
     66 {
     67 	unsigned char	xbyte;
     68 	ber_tag_t	tag;
     69 	char		*tagp;
     70 	int		i;
     71 
     72 	if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
     73 		return (KMFBER_DEFAULT);
     74 
     75 	if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
     76 		return ((ber_uint_t)xbyte);
     77 
     78 	tagp = (char *)&tag;
     79 	tagp[0] = xbyte;
     80 	for (i = 1; i < sizeof (ber_int_t); i++) {
     81 		if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
     82 			return (KMFBER_DEFAULT);
     83 
     84 		tagp[i] = xbyte;
     85 
     86 		if (! (xbyte & KMFBER_MORE_TAG_MASK))
     87 			break;
     88 	}
     89 
     90 	/* tag too big! */
     91 	if (i == sizeof (ber_int_t))
     92 		return (KMFBER_DEFAULT);
     93 
     94 	/* want leading, not trailing 0's */
     95 	return (tag >> (sizeof (ber_int_t)- i - 1));
     96 }
     97 
     98 /*
     99  * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
    100  * If that changes, the implementation of kmfber_peek_tag() will need to
    101  * be changed.
    102  */
    103 ber_tag_t
    104 kmfber_skip_tag(BerElement *ber, ber_len_t *len)
    105 {
    106 	ber_tag_t	tag;
    107 	unsigned char	lc;
    108 	int		noctets, diff;
    109 	uint32_t	netlen;
    110 
    111 	/*
    112 	 * Any ber element looks like this: tag length contents.
    113 	 * Assuming everything's ok, we return the tag byte (we
    114 	 * can assume a single byte), and return the length in len.
    115 	 *
    116 	 * Assumptions:
    117 	 *	1) definite lengths
    118 	 *	2) primitive encodings used whenever possible
    119 	 */
    120 
    121 	/*
    122 	 * First, we read the tag.
    123 	 */
    124 
    125 	if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
    126 		return (KMFBER_DEFAULT);
    127 
    128 	/*
    129 	 * Next, read the length.  The first byte contains the length of
    130 	 * the length.  If bit 8 is set, the length is the long form,
    131 	 * otherwise it's the short form.  We don't allow a length that's
    132 	 * greater than what we can hold in an unsigned long.
    133 	 */
    134 
    135 	*len = 0;
    136 	netlen = 0;
    137 	if (kmfber_read(ber, (char *)&lc, 1) != 1)
    138 		return (KMFBER_DEFAULT);
    139 	if (lc & 0x80) {
    140 		noctets = (lc & 0x7f);
    141 		if (noctets > sizeof (ber_uint_t))
    142 			return (KMFBER_DEFAULT);
    143 		diff = sizeof (ber_int_t) - noctets;
    144 		if (kmfber_read(ber, (char *)&netlen + diff, noctets)
    145 		    != noctets)
    146 			return (KMFBER_DEFAULT);
    147 		*len = ntohl(netlen);
    148 	} else {
    149 		*len = lc;
    150 	}
    151 
    152 	return (tag);
    153 }
    154 
    155 
    156 /*
    157  * Note: Previously, we passed the "ber" parameter directly to
    158  * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
    159  * We now take advantage of the fact that the only ber structure
    160  * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
    161  * If that changes, this code must change too.
    162  */
    163 static ber_tag_t
    164 kmfber_peek_tag(BerElement *ber, ber_len_t *len)
    165 {
    166 	BerElement	bercopy;
    167 
    168 	bercopy.ber_end = ber->ber_end;
    169 	bercopy.ber_ptr = ber->ber_ptr;
    170 	return (kmfber_skip_tag(&bercopy, len));
    171 }
    172 
    173 static int
    174 ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
    175 {
    176 	int i;
    177 	ber_int_t value;
    178 	unsigned char buffer[sizeof (ber_int_t)];
    179 	/*
    180 	 * The tag and length have already been stripped off.  We should
    181 	 * be sitting right before len bytes of 2's complement integer,
    182 	 * ready to be read straight into an int.  We may have to sign
    183 	 * extend after we read it in.
    184 	 */
    185 
    186 	if (len > sizeof (buffer))
    187 		return (-1);
    188 
    189 	/* read into the low-order bytes of netnum */
    190 	if (kmfber_read(ber, (char *)buffer, len) != len)
    191 		return (-1);
    192 
    193 	/* This sets the required sign extension */
    194 	if (len != 0) {
    195 		value = 0x80 & buffer[0] ? (-1) : 0;
    196 	} else {
    197 		value = 0;
    198 	}
    199 
    200 	for (i = 0; i < len; i++)
    201 		value = (value << 8) | buffer[i];
    202 
    203 	*num = value;
    204 
    205 	return (len);
    206 }
    207 
    208 static ber_tag_t
    209 kmfber_get_int(BerElement *ber, ber_int_t *num)
    210 {
    211 	ber_tag_t	tag;
    212 	ber_len_t	len;
    213 
    214 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
    215 		return (KMFBER_DEFAULT);
    216 
    217 	/*
    218 	 * len is being demoted to a long here --  possible conversion error
    219 	 */
    220 
    221 	if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
    222 		return (KMFBER_DEFAULT);
    223 	else
    224 		return (tag);
    225 }
    226 
    227 static ber_tag_t
    228 kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
    229 {
    230 	ber_len_t	datalen;
    231 	ber_tag_t	tag;
    232 #ifdef STR_TRANSLATION
    233 	char		*transbuf;
    234 #endif /* STR_TRANSLATION */
    235 
    236 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
    237 		return (KMFBER_DEFAULT);
    238 	if (datalen > (*len - 1))
    239 		return (KMFBER_DEFAULT);
    240 
    241 	/*
    242 	 * datalen is being demoted to a long here --  possible conversion error
    243 	 */
    244 
    245 	if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
    246 		return (KMFBER_DEFAULT);
    247 
    248 	buf[datalen] = '\0';
    249 
    250 #ifdef STR_TRANSLATION
    251 	if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
    252 	    != 0 && ber->ber_decode_translate_proc != NULL) {
    253 
    254 		transbuf = buf;
    255 		++datalen;
    256 		if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
    257 		    0) != 0) {
    258 			return (KMFBER_DEFAULT);
    259 		}
    260 		if (datalen > *len) {
    261 			free(transbuf);
    262 			return (KMFBER_DEFAULT);
    263 		}
    264 		(void) memmove(buf, transbuf, datalen);
    265 		free(transbuf);
    266 		--datalen;
    267 	}
    268 #endif /* STR_TRANSLATION */
    269 
    270 	*len = datalen;
    271 	return (tag);
    272 }
    273 
    274 static ber_tag_t
    275 kmfber_get_stringa(BerElement *ber, char **buf)
    276 {
    277 	ber_len_t	datalen;
    278 	ber_tag_t	tag;
    279 
    280 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
    281 		return (KMFBER_DEFAULT);
    282 
    283 	if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
    284 		return (KMFBER_DEFAULT);
    285 
    286 	/*
    287 	 * datalen is being demoted to a long here --  possible conversion error
    288 	 */
    289 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
    290 		return (KMFBER_DEFAULT);
    291 	(*buf)[datalen] = '\0';
    292 
    293 	return (tag);
    294 }
    295 
    296 ber_tag_t
    297 ber_get_oid(BerElement *ber, struct berval *oid)
    298 {
    299 	ber_len_t	len;
    300 	ber_tag_t	tag;
    301 
    302 	if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
    303 		return (KMFBER_DEFAULT);
    304 	}
    305 
    306 	if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
    307 		return (KMFBER_DEFAULT);
    308 	}
    309 	oid->bv_len = len;
    310 
    311 	if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
    312 	    (ber_slen_t)oid->bv_len)
    313 		return (KMFBER_DEFAULT);
    314 
    315 	return (tag);
    316 }
    317 
    318 ber_tag_t
    319 ber_get_bigint(BerElement *ber, struct berval **bv)
    320 {
    321 	ber_len_t	len;
    322 	ber_tag_t	tag;
    323 
    324 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
    325 	    == NULL) {
    326 		return (KMFBER_DEFAULT);
    327 	}
    328 	(*bv)->bv_len = 0;
    329 	(*bv)->bv_val = NULL;
    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 		if (sss == NULL)
    595 			break;
    596 		*sss = NULL;
    597 		j = 0;
    598 		array_size = 0;
    599 		for (tag = kmfber_first_element(ber, &len, &last);
    600 		    (tag != KMFBER_DEFAULT &&
    601 		    tag != KMFBER_END_OF_SEQORSET &&
    602 		    rc != KMFBER_DEFAULT);
    603 		    tag = kmfber_next_element(ber, &len, last)) {
    604 			if (*sss == NULL) {
    605 				/* Make room for at least 15 strings */
    606 				*sss = (char **)malloc(16 * sizeof (char *));
    607 				array_size = 16;
    608 			} else {
    609 				if ((size_t)(j+2) > array_size) {
    610 					/* We'v overflowed our buffer */
    611 					*sss = (char **)realloc(*sss,
    612 					    (array_size * 2) * sizeof (char *));
    613 					array_size = array_size * 2;
    614 				}
    615 			}
    616 			rc = kmfber_get_stringa(ber, &((*sss)[j]));
    617 			j++;
    618 		}
    619 		if (rc != KMFBER_DEFAULT && tag != KMFBER_END_OF_SEQORSET) {
    620 			rc = KMFBER_DEFAULT;
    621 		}
    622 		if (j > 0)
    623 			(*sss)[j] = NULL;
    624 		break;
    625 
    626 		case 'V':	/* sequence of strings + lengths */
    627 		bv = va_arg(ap, struct berval ***);
    628 		*bv = NULL;
    629 		j = 0;
    630 		for (tag = kmfber_first_element(ber, &len, &last);
    631 		    (tag != KMFBER_DEFAULT &&
    632 		    tag != KMFBER_END_OF_SEQORSET &&
    633 		    rc != KMFBER_DEFAULT);
    634 		    tag = kmfber_next_element(ber, &len, last)) {
    635 			if (*bv == NULL) {
    636 				*bv = (struct berval **)malloc(
    637 				    2 * sizeof (struct berval *));
    638 			} else {
    639 				*bv = (struct berval **)realloc(*bv,
    640 				    (j + 2) * sizeof (struct berval *));
    641 			}
    642 			rc = kmfber_get_stringal(ber, &((*bv)[j]));
    643 			j++;
    644 		}
    645 		if (rc != KMFBER_DEFAULT &&
    646 		    tag != KMFBER_END_OF_SEQORSET) {
    647 			rc = KMFBER_DEFAULT;
    648 		}
    649 		if (j > 0)
    650 			(*bv)[j] = NULL;
    651 		break;
    652 
    653 		case 'x':	/* skip the next element - whatever it is */
    654 		if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
    655 			break;
    656 		ber->ber_ptr += len;
    657 		break;
    658 
    659 		case '{':	/* begin sequence */
    660 		case '[':	/* begin set */
    661 		if (*(p + 1) != 'v' && *(p + 1) != 'V')
    662 			rc = kmfber_skip_tag(ber, &len);
    663 		break;
    664 
    665 		case '}':	/* end sequence */
    666 		case ']':	/* end set */
    667 		break;
    668 
    669 		default:
    670 		rc = KMFBER_DEFAULT;
    671 		break;
    672 		}
    673 	}
    674 
    675 
    676 	va_end(ap);
    677 	if (rc == KMFBER_DEFAULT) {
    678 	va_start(ap, fmt);
    679 	for (p--; fmt < p && *fmt; fmt++) {
    680 		switch (*fmt) {
    681 		case 'a':	/* octet string - allocate storage as needed */
    682 			ss = va_arg(ap, char **);
    683 			if (ss != NULL && *ss != NULL) {
    684 				free(*ss);
    685 				*ss = NULL;
    686 			}
    687 			break;
    688 
    689 		case 'b':	/* boolean */
    690 			i = va_arg(ap, int *);
    691 			break;
    692 
    693 		case 'e':	/* enumerated */
    694 		case 'i':	/* int */
    695 			l = va_arg(ap, ber_slen_t *);
    696 			break;
    697 
    698 		case 'l':	/* length of next item */
    699 			l = va_arg(ap, ber_slen_t *);
    700 			break;
    701 
    702 		case 'n':	/* null */
    703 			break;
    704 
    705 		case 's':	/* octet string - in a buffer */
    706 			s = va_arg(ap, char *);
    707 			l = va_arg(ap, ber_slen_t *);
    708 			break;
    709 
    710 		case 'o':	/* octet string in a supplied berval */
    711 			bval = va_arg(ap, struct berval *);
    712 			if (bval->bv_val) free(bval->bv_val);
    713 			(void) memset(bval, 0, sizeof (struct berval));
    714 			break;
    715 
    716 		case 'O':	/* octet string - allocate & include length */
    717 			bvp = va_arg(ap, struct berval **);
    718 			kmfber_bvfree(*bvp);
    719 			bvp = NULL;
    720 			break;
    721 
    722 		case 'B':	/* bit string - allocate storage as needed */
    723 			ss = va_arg(ap, char **);
    724 			l = va_arg(ap, ber_slen_t *); /* for length, in bits */
    725 			if (ss != NULL && *ss != NULL) {
    726 				free(*ss);
    727 				*ss = NULL;
    728 			}
    729 			break;
    730 
    731 		case 't':	/* tag of next item */
    732 			t = va_arg(ap, ber_tag_t *);
    733 			break;
    734 		case 'T':	/* skip tag of next item */
    735 			t = va_arg(ap, ber_tag_t *);
    736 			break;
    737 
    738 		case 'v':	/* sequence of strings */
    739 			sss = va_arg(ap, char ***);
    740 			if (sss != NULL && *sss != NULL) {
    741 				ber_svecfree(*sss);
    742 				*sss = NULL;
    743 			}
    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 	return (rc);
    771 }
    772 
    773 struct berval *
    774 kmfber_bvdup(const struct berval *bv)
    775 {
    776 	struct berval	*new;
    777 
    778 	if ((new = (struct berval *)malloc(sizeof (struct berval)))
    779 	    == NULL) {
    780 		return (NULL);
    781 	}
    782 	if (bv->bv_val == NULL) {
    783 		new->bv_val = NULL;
    784 		new->bv_len = 0;
    785 	} else {
    786 		if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
    787 		    == NULL) {
    788 			return (NULL);
    789 		}
    790 		(void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
    791 		new->bv_val[bv->bv_len] = '\0';
    792 		new->bv_len = bv->bv_len;
    793 	}
    794 
    795 	return (new);
    796 }
    797