13089Swyllys /*
2*6051Swyllys  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
33089Swyllys  * Use is subject to license terms.
43089Swyllys  */
53089Swyllys /*
63089Swyllys  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
73089Swyllys  *
83089Swyllys  * The contents of this file are subject to the Netscape Public License
93089Swyllys  * Version 1.0 (the "NPL"); you may not use this file except in
103089Swyllys  * compliance with the NPL.  You may obtain a copy of the NPL at
113089Swyllys  * http://www.mozilla.org/NPL/
123089Swyllys  *
133089Swyllys  * Software distributed under the NPL is distributed on an "AS IS" basis,
143089Swyllys  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
153089Swyllys  * for the specific language governing rights and limitations under the
163089Swyllys  * NPL.
173089Swyllys  *
183089Swyllys  * The Initial Developer of this code under the NPL is Netscape
193089Swyllys  * Communications Corporation.  Portions created by Netscape are
203089Swyllys  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
213089Swyllys  * Reserved.
223089Swyllys  */
233089Swyllys 
243089Swyllys /*
253089Swyllys  * Copyright (c) 1990 Regents of the University of Michigan.
263089Swyllys  * All rights reserved.
273089Swyllys  *
283089Swyllys  * Redistribution and use in source and binary forms are permitted
293089Swyllys  * provided that this notice is preserved and that due credit is given
303089Swyllys  * to the University of Michigan at Ann Arbor. The name of the University
313089Swyllys  * may not be used to endorse or promote products derived from this
323089Swyllys  * software without specific prior written permission. This software
333089Swyllys  * is provided ``as is'' without express or implied warranty.
343089Swyllys  */
353089Swyllys 
363089Swyllys /* decode.c - ber input decoding routines */
373089Swyllys 
383089Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
393089Swyllys 
403089Swyllys #include <strings.h>
413089Swyllys #include <sys/types.h>
423089Swyllys #include <netinet/in.h>
433089Swyllys #include <inttypes.h>
443089Swyllys 
453089Swyllys #include <ber_der.h>
463089Swyllys #include "kmfber_int.h"
473089Swyllys 
483089Swyllys static void
493089Swyllys ber_svecfree(char **vals)
503089Swyllys {
513089Swyllys 	int	i;
523089Swyllys 
533089Swyllys 	if (vals == NULL)
543089Swyllys 		return;
553089Swyllys 	for (i = 0; vals[i] != NULL; i++)
563089Swyllys 		free(vals[i]);
573089Swyllys 	free((char *)vals);
583089Swyllys }
593089Swyllys 
603089Swyllys /*
613089Swyllys  * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
623089Swyllys  * If that changes, the kmfber_peek_tag() and/or
633089Swyllys  * kmfkmfber_skip_tag() implementations will need to be changed.
643089Swyllys  */
653089Swyllys /* return the tag - KMFBER_DEFAULT returned means trouble */
663089Swyllys static ber_tag_t
673089Swyllys kmfber_get_tag(BerElement *ber)
683089Swyllys {
693089Swyllys 	unsigned char	xbyte;
703089Swyllys 	ber_tag_t	tag;
713089Swyllys 	char		*tagp;
723089Swyllys 	int		i;
733089Swyllys 
743089Swyllys 	if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
753089Swyllys 		return (KMFBER_DEFAULT);
763089Swyllys 
773089Swyllys 	if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
783089Swyllys 		return ((ber_uint_t)xbyte);
793089Swyllys 
803089Swyllys 	tagp = (char *)&tag;
813089Swyllys 	tagp[0] = xbyte;
823089Swyllys 	for (i = 1; i < sizeof (ber_int_t); i++) {
833089Swyllys 		if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
843089Swyllys 			return (KMFBER_DEFAULT);
853089Swyllys 
863089Swyllys 		tagp[i] = xbyte;
873089Swyllys 
883089Swyllys 		if (! (xbyte & KMFBER_MORE_TAG_MASK))
893089Swyllys 			break;
903089Swyllys 	}
913089Swyllys 
923089Swyllys 	/* tag too big! */
933089Swyllys 	if (i == sizeof (ber_int_t))
943089Swyllys 		return (KMFBER_DEFAULT);
953089Swyllys 
963089Swyllys 	/* want leading, not trailing 0's */
973089Swyllys 	return (tag >> (sizeof (ber_int_t)- i - 1));
983089Swyllys }
993089Swyllys 
1003089Swyllys /*
1013089Swyllys  * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
1023089Swyllys  * If that changes, the implementation of kmfber_peek_tag() will need to
1033089Swyllys  * be changed.
1043089Swyllys  */
1053089Swyllys ber_tag_t
1063089Swyllys kmfber_skip_tag(BerElement *ber, ber_len_t *len)
1073089Swyllys {
1083089Swyllys 	ber_tag_t	tag;
1093089Swyllys 	unsigned char	lc;
1103089Swyllys 	int		noctets, diff;
1113089Swyllys 	uint32_t	netlen;
1123089Swyllys 
1133089Swyllys 	/*
1143089Swyllys 	 * Any ber element looks like this: tag length contents.
1153089Swyllys 	 * Assuming everything's ok, we return the tag byte (we
1163089Swyllys 	 * can assume a single byte), and return the length in len.
1173089Swyllys 	 *
1183089Swyllys 	 * Assumptions:
1193089Swyllys 	 *	1) definite lengths
1203089Swyllys 	 *	2) primitive encodings used whenever possible
1213089Swyllys 	 */
1223089Swyllys 
1233089Swyllys 	/*
1243089Swyllys 	 * First, we read the tag.
1253089Swyllys 	 */
1263089Swyllys 
1273089Swyllys 	if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
1283089Swyllys 		return (KMFBER_DEFAULT);
1293089Swyllys 
1303089Swyllys 	/*
1313089Swyllys 	 * Next, read the length.  The first byte contains the length of
1323089Swyllys 	 * the length.  If bit 8 is set, the length is the long form,
1333089Swyllys 	 * otherwise it's the short form.  We don't allow a length that's
1343089Swyllys 	 * greater than what we can hold in an unsigned long.
1353089Swyllys 	 */
1363089Swyllys 
1373089Swyllys 	*len = 0;
1383089Swyllys 	netlen = 0;
1393089Swyllys 	if (kmfber_read(ber, (char *)&lc, 1) != 1)
1403089Swyllys 		return (KMFBER_DEFAULT);
1413089Swyllys 	if (lc & 0x80) {
1423089Swyllys 		noctets = (lc & 0x7f);
1433089Swyllys 		if (noctets > sizeof (ber_uint_t))
1443089Swyllys 			return (KMFBER_DEFAULT);
1453089Swyllys 		diff = sizeof (ber_int_t) - noctets;
1463089Swyllys 		if (kmfber_read(ber, (char *)&netlen + diff, noctets)
147*6051Swyllys 		    != noctets)
1483089Swyllys 			return (KMFBER_DEFAULT);
1493089Swyllys 		*len = ntohl(netlen);
1503089Swyllys 	} else {
1513089Swyllys 		*len = lc;
1523089Swyllys 	}
1533089Swyllys 
1543089Swyllys 	return (tag);
1553089Swyllys }
1563089Swyllys 
1573089Swyllys 
1583089Swyllys /*
1593089Swyllys  * Note: Previously, we passed the "ber" parameter directly to
1603089Swyllys  * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
1613089Swyllys  * We now take advantage of the fact that the only ber structure
1623089Swyllys  * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
1633089Swyllys  * If that changes, this code must change too.
1643089Swyllys  */
1653089Swyllys static ber_tag_t
1663089Swyllys kmfber_peek_tag(BerElement *ber, ber_len_t *len)
1673089Swyllys {
1683089Swyllys 	BerElement	bercopy;
1693089Swyllys 
1703089Swyllys 	bercopy.ber_end = ber->ber_end;
1713089Swyllys 	bercopy.ber_ptr = ber->ber_ptr;
1723089Swyllys 	return (kmfber_skip_tag(&bercopy, len));
1733089Swyllys }
1743089Swyllys 
1753089Swyllys static int
1763089Swyllys ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
1773089Swyllys {
1783089Swyllys 	int i;
1793089Swyllys 	ber_int_t value;
1803089Swyllys 	unsigned char buffer[sizeof (ber_int_t)];
1813089Swyllys 	/*
1823089Swyllys 	 * The tag and length have already been stripped off.  We should
1833089Swyllys 	 * be sitting right before len bytes of 2's complement integer,
1843089Swyllys 	 * ready to be read straight into an int.  We may have to sign
1853089Swyllys 	 * extend after we read it in.
1863089Swyllys 	 */
1873089Swyllys 
1883089Swyllys 	if (len > sizeof (ber_slen_t))
1893089Swyllys 		return (-1);
1903089Swyllys 
1913089Swyllys 	/* read into the low-order bytes of netnum */
1923089Swyllys 	if (kmfber_read(ber, (char *)buffer, len) != len)
1933089Swyllys 		return (-1);
1943089Swyllys 
1953089Swyllys 	/* This sets the required sign extension */
1963089Swyllys 	if (len != 0) {
1973089Swyllys 		value = 0x80 & buffer[0] ? (-1) : 0;
1983089Swyllys 	} else {
1993089Swyllys 		value = 0;
2003089Swyllys 	}
2013089Swyllys 
2023089Swyllys 	for (i = 0; i < len; i++)
2033089Swyllys 		value = (value << 8) | buffer[i];
2043089Swyllys 
2053089Swyllys 	*num = value;
2063089Swyllys 
2073089Swyllys 	return (len);
2083089Swyllys }
2093089Swyllys 
2103089Swyllys static ber_tag_t
2113089Swyllys kmfber_get_int(BerElement *ber, ber_int_t *num)
2123089Swyllys {
2133089Swyllys 	ber_tag_t	tag;
2143089Swyllys 	ber_len_t	len;
2153089Swyllys 
2163089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
2173089Swyllys 		return (KMFBER_DEFAULT);
2183089Swyllys 
2193089Swyllys 	/*
2203089Swyllys 	 * len is being demoted to a long here --  possible conversion error
2213089Swyllys 	 */
2223089Swyllys 
2233089Swyllys 	if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
2243089Swyllys 		return (KMFBER_DEFAULT);
2253089Swyllys 	else
2263089Swyllys 		return (tag);
2273089Swyllys }
2283089Swyllys 
2293089Swyllys static ber_tag_t
2303089Swyllys kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
2313089Swyllys {
2323089Swyllys 	ber_len_t	datalen;
2333089Swyllys 	ber_tag_t	tag;
2343089Swyllys #ifdef STR_TRANSLATION
2353089Swyllys 	char		*transbuf;
2363089Swyllys #endif /* STR_TRANSLATION */
2373089Swyllys 
2383089Swyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
2393089Swyllys 		return (KMFBER_DEFAULT);
2403089Swyllys 	if (datalen > (*len - 1))
2413089Swyllys 		return (KMFBER_DEFAULT);
2423089Swyllys 
2433089Swyllys 	/*
2443089Swyllys 	 * datalen is being demoted to a long here --  possible conversion error
2453089Swyllys 	 */
2463089Swyllys 
2473089Swyllys 	if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
2483089Swyllys 		return (KMFBER_DEFAULT);
2493089Swyllys 
2503089Swyllys 	buf[datalen] = '\0';
2513089Swyllys 
2523089Swyllys #ifdef STR_TRANSLATION
2533089Swyllys 	if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
254*6051Swyllys 	    != 0 && ber->ber_decode_translate_proc != NULL) {
2553089Swyllys 
2563089Swyllys 		transbuf = buf;
2573089Swyllys 		++datalen;
2583089Swyllys 		if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
259*6051Swyllys 		    0) != 0) {
2603089Swyllys 			return (KMFBER_DEFAULT);
2613089Swyllys 		}
2623089Swyllys 		if (datalen > *len) {
2633089Swyllys 			free(transbuf);
2643089Swyllys 			return (KMFBER_DEFAULT);
2653089Swyllys 		}
2663089Swyllys 		(void) memmove(buf, transbuf, datalen);
2673089Swyllys 		free(transbuf);
2683089Swyllys 		--datalen;
2693089Swyllys 	}
2703089Swyllys #endif /* STR_TRANSLATION */
2713089Swyllys 
2723089Swyllys 	*len = datalen;
2733089Swyllys 	return (tag);
2743089Swyllys }
2753089Swyllys 
2763089Swyllys static ber_tag_t
2773089Swyllys kmfber_get_stringa(BerElement *ber, char **buf)
2783089Swyllys {
2793089Swyllys 	ber_len_t	datalen;
2803089Swyllys 	ber_tag_t	tag;
2813089Swyllys 
2823089Swyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
2833089Swyllys 		return (KMFBER_DEFAULT);
2843089Swyllys 
2853089Swyllys 	if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
2863089Swyllys 		return (KMFBER_DEFAULT);
2873089Swyllys 
2883089Swyllys 	/*
2893089Swyllys 	 * datalen is being demoted to a long here --  possible conversion error
2903089Swyllys 	 */
2913089Swyllys 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
2923089Swyllys 		return (KMFBER_DEFAULT);
2933089Swyllys 	(*buf)[datalen] = '\0';
2943089Swyllys 
2953089Swyllys 	return (tag);
2963089Swyllys }
2973089Swyllys 
2983089Swyllys ber_tag_t
2993089Swyllys ber_get_oid(BerElement *ber, struct berval *oid)
3003089Swyllys {
3013089Swyllys 	ber_len_t	len;
3023089Swyllys 	ber_tag_t	tag;
3033089Swyllys 
3043089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
3053089Swyllys 		return (KMFBER_DEFAULT);
3063089Swyllys 	}
3073089Swyllys 
3083089Swyllys 	if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
3093089Swyllys 		return (KMFBER_DEFAULT);
3103089Swyllys 	}
3113089Swyllys 	oid->bv_len = len;
3123089Swyllys 
3133089Swyllys 	if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
314*6051Swyllys 	    (ber_slen_t)oid->bv_len)
3153089Swyllys 		return (KMFBER_DEFAULT);
3163089Swyllys 
3173089Swyllys 	return (tag);
3183089Swyllys }
3193089Swyllys 
3203089Swyllys ber_tag_t
3213089Swyllys ber_get_bigint(BerElement *ber, struct berval **bv)
3223089Swyllys {
3233089Swyllys 	ber_len_t	len;
3243089Swyllys 	ber_tag_t	tag;
3253089Swyllys 
3263089Swyllys 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
327*6051Swyllys 	    == NULL) {
3283089Swyllys 		return (KMFBER_DEFAULT);
3293089Swyllys 	}
330*6051Swyllys 	(*bv)->bv_len = 0;
331*6051Swyllys 	(*bv)->bv_val = NULL;
3323089Swyllys 
3333089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
3343089Swyllys 		return (KMFBER_DEFAULT);
3353089Swyllys 	}
3363089Swyllys 
3373089Swyllys 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
338*6051Swyllys 	    == NULL) {
3393089Swyllys 		return (KMFBER_DEFAULT);
3403089Swyllys 	}
3413089Swyllys 
3423089Swyllys 	/*
3433089Swyllys 	 * len is being demoted to a long here --  possible conversion error
3443089Swyllys 	 */
3453089Swyllys 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
3463089Swyllys 		return (KMFBER_DEFAULT);
3473089Swyllys 
3483089Swyllys 	(*bv)->bv_len = len;
3493089Swyllys 
3503089Swyllys 	/* If DER encoding, strip leading 0's */
3513089Swyllys 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
3523089Swyllys 		char *p = (*bv)->bv_val;
3533089Swyllys 		while ((*p == 0x00) && ((*bv)->bv_len > 0)) {
3543089Swyllys 			p++;
3553089Swyllys 			(*bv)->bv_len--;
3563089Swyllys 		}
3573089Swyllys 		/*
3583089Swyllys 		 * Shift the buffer to the beginning of the allocated space
3593089Swyllys 		 * so it can be properly freed later.
3603089Swyllys 		 */
3613089Swyllys 		if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
3623089Swyllys 			(void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
3633089Swyllys 	}
3643089Swyllys 
3653089Swyllys 	return (tag);
3663089Swyllys }
3673089Swyllys 
3683089Swyllys static ber_tag_t
3693089Swyllys kmfber_get_stringal(BerElement *ber, struct berval **bv)
3703089Swyllys {
3713089Swyllys 	ber_len_t	len;
3723089Swyllys 	ber_tag_t	tag;
3733089Swyllys 
3743089Swyllys 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
375*6051Swyllys 	    == NULL) {
3763089Swyllys 		return (KMFBER_DEFAULT);
3773089Swyllys 	}
3783089Swyllys 
3793089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
3803089Swyllys 		return (KMFBER_DEFAULT);
3813089Swyllys 	}
3823089Swyllys 
3833089Swyllys 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
384*6051Swyllys 	    == NULL) {
3853089Swyllys 		return (KMFBER_DEFAULT);
3863089Swyllys 	}
3873089Swyllys 
3883089Swyllys 	/*
3893089Swyllys 	 * len is being demoted to a long here --  possible conversion error
3903089Swyllys 	 */
3913089Swyllys 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
3923089Swyllys 		return (KMFBER_DEFAULT);
3933089Swyllys 	((*bv)->bv_val)[len] = '\0';
3943089Swyllys 	(*bv)->bv_len = len;
3953089Swyllys 
3963089Swyllys 	return (tag);
3973089Swyllys }
3983089Swyllys 
3993089Swyllys static ber_tag_t
4003089Swyllys kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
4013089Swyllys {
4023089Swyllys 	ber_len_t	datalen;
4033089Swyllys 	ber_tag_t	tag;
4043089Swyllys 	unsigned char	unusedbits;
4053089Swyllys 
4063089Swyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
4073089Swyllys 		return (KMFBER_DEFAULT);
4083089Swyllys 
4093089Swyllys 	if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
4103089Swyllys 		return (KMFBER_DEFAULT);
4113089Swyllys 
4123089Swyllys 	if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
4133089Swyllys 		return (KMFBER_DEFAULT);
4143089Swyllys 
4153089Swyllys 	/* Subtract 1 for the unused bits */
4163089Swyllys 	datalen--;
4173089Swyllys 
4183089Swyllys 	/*
4193089Swyllys 	 * datalen is being demoted to a long here --  possible conversion error
4203089Swyllys 	 */
4213089Swyllys 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
4223089Swyllys 		return (KMFBER_DEFAULT);
4233089Swyllys 
4243089Swyllys 	*blen = datalen * 8 - unusedbits;
4253089Swyllys 	return (tag);
4263089Swyllys }
4273089Swyllys 
4283089Swyllys static ber_tag_t
4293089Swyllys kmfber_get_null(BerElement *ber)
4303089Swyllys {
4313089Swyllys 	ber_len_t	len;
4323089Swyllys 	ber_tag_t tag;
4333089Swyllys 
4343089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
4353089Swyllys 		return (KMFBER_DEFAULT);
4363089Swyllys 
4373089Swyllys 	if (len != 0)
4383089Swyllys 		return (KMFBER_DEFAULT);
4393089Swyllys 
4403089Swyllys 	return (tag);
4413089Swyllys }
4423089Swyllys 
4433089Swyllys static ber_tag_t
4443089Swyllys kmfber_get_boolean(BerElement *ber, int *boolval)
4453089Swyllys {
4463089Swyllys 	ber_int_t	longbool;
4473089Swyllys 	int		rc;
4483089Swyllys 
4493089Swyllys 	rc = kmfber_get_int(ber, &longbool);
4503089Swyllys 	*boolval = longbool;
4513089Swyllys 
4523089Swyllys 	return (rc);
4533089Swyllys }
4543089Swyllys 
4553089Swyllys ber_tag_t
4563089Swyllys kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
4573089Swyllys {
4583089Swyllys 	/* skip the sequence header, use the len to mark where to stop */
4593089Swyllys 	if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
4603089Swyllys 		return (KMFBER_ERROR);
4613089Swyllys 	}
4623089Swyllys 
4633089Swyllys 	*last = ber->ber_ptr + *len;
4643089Swyllys 
4653089Swyllys 	if (*last == ber->ber_ptr) {
4663089Swyllys 		return (KMFBER_END_OF_SEQORSET);
4673089Swyllys 	}
4683089Swyllys 
4693089Swyllys 	return (kmfber_peek_tag(ber, len));
4703089Swyllys }
4713089Swyllys 
4723089Swyllys ber_tag_t
4733089Swyllys kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
4743089Swyllys {
4753089Swyllys 	if (ber->ber_ptr == last) {
4763089Swyllys 		return (KMFBER_END_OF_SEQORSET);
4773089Swyllys 	}
4783089Swyllys 
4793089Swyllys 	return (kmfber_peek_tag(ber, len));
4803089Swyllys }
4813089Swyllys 
4823089Swyllys void
4833089Swyllys kmfber_bvfree(struct berval *bv)
4843089Swyllys {
4853089Swyllys 	if (bv != NULL) {
4863089Swyllys 		if (bv->bv_val != NULL) {
4873089Swyllys 			free(bv->bv_val);
4883089Swyllys 		}
4893089Swyllys 		free((char *)bv);
4903089Swyllys 	}
4913089Swyllys }
4923089Swyllys 
4933089Swyllys void
4943089Swyllys kmfber_bvecfree(struct berval **bv)
4953089Swyllys {
4963089Swyllys 	int	i;
4973089Swyllys 
4983089Swyllys 	if (bv != NULL) {
4993089Swyllys 		for (i = 0; bv[i] != NULL; i++) {
5003089Swyllys 			kmfber_bvfree(bv[i]);
5013089Swyllys 		}
5023089Swyllys 		free((char *)bv);
5033089Swyllys 	}
5043089Swyllys }
5053089Swyllys 
5063089Swyllys /* VARARGS */
5073089Swyllys ber_tag_t
5083089Swyllys kmfber_scanf(BerElement *ber, const char *fmt, ...)
5093089Swyllys {
5103089Swyllys 	va_list		ap;
5113089Swyllys 	char		*last, *p;
5123089Swyllys 	char		*s, **ss, ***sss;
5133089Swyllys 	struct berval 	***bv, **bvp, *bval;
5143089Swyllys 	int		*i, j;
5153089Swyllys 	ber_slen_t	*l;
5163089Swyllys 	ber_int_t	rc, tag, *b_int;
5173089Swyllys 	ber_tag_t	*t;
5183089Swyllys 	ber_len_t	len;
5193089Swyllys 	size_t		array_size;
5203089Swyllys 
5213089Swyllys 	va_start(ap, fmt);
5223089Swyllys 
5233089Swyllys 	for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
5243089Swyllys 	switch (*p) {
525*6051Swyllys 		case 'a':	/* octet string - allocate storage as needed */
5263089Swyllys 		ss = va_arg(ap, char **);
5273089Swyllys 		rc = kmfber_get_stringa(ber, ss);
5283089Swyllys 		break;
5293089Swyllys 
530*6051Swyllys 		case 'b':	/* boolean */
5313089Swyllys 		i = va_arg(ap, int *);
5323089Swyllys 		rc = kmfber_get_boolean(ber, i);
5333089Swyllys 		break;
5343089Swyllys 
535*6051Swyllys 		case 'D':	/* Object ID */
5363089Swyllys 		bval = va_arg(ap, struct berval *);
5373089Swyllys 		rc = ber_get_oid(ber, bval);
5383089Swyllys 		break;
539*6051Swyllys 		case 'e':	/* enumerated */
540*6051Swyllys 		case 'i':	/* int */
5413089Swyllys 		b_int = va_arg(ap, ber_int_t *);
5423089Swyllys 		rc = kmfber_get_int(ber, b_int);
5433089Swyllys 		break;
5443089Swyllys 
545*6051Swyllys 		case 'l':	/* length of next item */
5463089Swyllys 		l = va_arg(ap, ber_slen_t *);
5473089Swyllys 		rc = kmfber_peek_tag(ber, (ber_len_t *)l);
5483089Swyllys 		break;
5493089Swyllys 
550*6051Swyllys 		case 'n':	/* null */
5513089Swyllys 		rc = kmfber_get_null(ber);
5523089Swyllys 		break;
5533089Swyllys 
554*6051Swyllys 		case 's':	/* octet string - in a buffer */
5553089Swyllys 		s = va_arg(ap, char *);
5563089Swyllys 		l = va_arg(ap, ber_slen_t *);
5573089Swyllys 		rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
5583089Swyllys 		break;
5593089Swyllys 
560*6051Swyllys 		case 'o':	/* octet string in a supplied berval */
5613089Swyllys 		bval = va_arg(ap, struct berval *);
5623089Swyllys 		(void) kmfber_peek_tag(ber, &bval->bv_len);
5633089Swyllys 		rc = kmfber_get_stringa(ber, &bval->bv_val);
5643089Swyllys 		break;
5653089Swyllys 
566*6051Swyllys 		case 'I': /* variable length Integer */
5673089Swyllys 		/* Treat INTEGER same as an OCTET string, but ignore the tag */
5683089Swyllys 		bvp = va_arg(ap, struct berval **);
5693089Swyllys 		rc = ber_get_bigint(ber, bvp);
5703089Swyllys 		break;
571*6051Swyllys 		case 'O': /* octet string - allocate & include length */
5723089Swyllys 		bvp = va_arg(ap, struct berval **);
5733089Swyllys 		rc = kmfber_get_stringal(ber, bvp);
5743089Swyllys 		break;
5753089Swyllys 
576*6051Swyllys 		case 'B':	/* bit string - allocate storage as needed */
5773089Swyllys 		ss = va_arg(ap, char **);
5783089Swyllys 		l = va_arg(ap, ber_slen_t *); /* for length, in bits */
5793089Swyllys 		rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
5803089Swyllys 		break;
5813089Swyllys 
582*6051Swyllys 		case 't':	/* tag of next item */
5833089Swyllys 		t = va_arg(ap, ber_tag_t *);
5843089Swyllys 		*t = kmfber_peek_tag(ber, &len);
5853089Swyllys 		rc = (ber_int_t)(*t);
5863089Swyllys 		break;
5873089Swyllys 
588*6051Swyllys 		case 'T':	/* skip tag of next item */
5893089Swyllys 		t = va_arg(ap, ber_tag_t *);
5903089Swyllys 		*t = kmfber_skip_tag(ber, &len);
5913089Swyllys 		rc = (ber_int_t)(*t);
5923089Swyllys 		break;
5933089Swyllys 
594*6051Swyllys 		case 'v':	/* sequence of strings */
5953089Swyllys 		sss = va_arg(ap, char ***);
596*6051Swyllys 		if (sss == NULL)
597*6051Swyllys 			break;
5983089Swyllys 		*sss = NULL;
5993089Swyllys 		j = 0;
6003089Swyllys 		array_size = 0;
6013089Swyllys 		for (tag = kmfber_first_element(ber, &len, &last);
602*6051Swyllys 		    (tag != KMFBER_DEFAULT &&
603*6051Swyllys 		    tag != KMFBER_END_OF_SEQORSET &&
604*6051Swyllys 		    rc != KMFBER_DEFAULT);
605*6051Swyllys 		    tag = kmfber_next_element(ber, &len, last)) {
606*6051Swyllys 			if (*sss == NULL) {
607*6051Swyllys 				/* Make room for at least 15 strings */
608*6051Swyllys 				*sss = (char **)malloc(16 * sizeof (char *));
609*6051Swyllys 				array_size = 16;
610*6051Swyllys 			} else {
611*6051Swyllys 				if ((size_t)(j+2) > array_size) {
612*6051Swyllys 					/* We'v overflowed our buffer */
613*6051Swyllys 					*sss = (char **)realloc(*sss,
614*6051Swyllys 					    (array_size * 2) * sizeof (char *));
615*6051Swyllys 					array_size = array_size * 2;
616*6051Swyllys 				}
6173089Swyllys 			}
618*6051Swyllys 			rc = kmfber_get_stringa(ber, &((*sss)[j]));
619*6051Swyllys 			j++;
6203089Swyllys 		}
621*6051Swyllys 		if (rc != KMFBER_DEFAULT && tag != KMFBER_END_OF_SEQORSET) {
622*6051Swyllys 			rc = KMFBER_DEFAULT;
6233089Swyllys 		}
6243089Swyllys 		if (j > 0)
625*6051Swyllys 			(*sss)[j] = NULL;
6263089Swyllys 		break;
6273089Swyllys 
628*6051Swyllys 		case 'V':	/* sequence of strings + lengths */
6293089Swyllys 		bv = va_arg(ap, struct berval ***);
6303089Swyllys 		*bv = NULL;
6313089Swyllys 		j = 0;
6323089Swyllys 		for (tag = kmfber_first_element(ber, &len, &last);
633*6051Swyllys 		    (tag != KMFBER_DEFAULT &&
634*6051Swyllys 		    tag != KMFBER_END_OF_SEQORSET &&
635*6051Swyllys 		    rc != KMFBER_DEFAULT);
636*6051Swyllys 		    tag = kmfber_next_element(ber, &len, last)) {
637*6051Swyllys 			if (*bv == NULL) {
638*6051Swyllys 				*bv = (struct berval **)malloc(
639*6051Swyllys 				    2 * sizeof (struct berval *));
640*6051Swyllys 			} else {
641*6051Swyllys 				*bv = (struct berval **)realloc(*bv,
642*6051Swyllys 				    (j + 2) * sizeof (struct berval *));
643*6051Swyllys 			}
644*6051Swyllys 			rc = kmfber_get_stringal(ber, &((*bv)[j]));
645*6051Swyllys 			j++;
6463089Swyllys 		}
6473089Swyllys 		if (rc != KMFBER_DEFAULT &&
648*6051Swyllys 		    tag != KMFBER_END_OF_SEQORSET) {
649*6051Swyllys 			rc = KMFBER_DEFAULT;
6503089Swyllys 		}
6513089Swyllys 		if (j > 0)
652*6051Swyllys 			(*bv)[j] = NULL;
6533089Swyllys 		break;
6543089Swyllys 
655*6051Swyllys 		case 'x':	/* skip the next element - whatever it is */
6563089Swyllys 		if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
657*6051Swyllys 			break;
6583089Swyllys 		ber->ber_ptr += len;
6593089Swyllys 		break;
6603089Swyllys 
661*6051Swyllys 		case '{':	/* begin sequence */
662*6051Swyllys 		case '[':	/* begin set */
6633089Swyllys 		if (*(p + 1) != 'v' && *(p + 1) != 'V')
664*6051Swyllys 			rc = kmfber_skip_tag(ber, &len);
6653089Swyllys 		break;
6663089Swyllys 
667*6051Swyllys 		case '}':	/* end sequence */
668*6051Swyllys 		case ']':	/* end set */
669*6051Swyllys 		break;
670*6051Swyllys 
671*6051Swyllys 		default:
6723089Swyllys 		rc = KMFBER_DEFAULT;
6733089Swyllys 		break;
674*6051Swyllys 		}
6753089Swyllys 	}
6763089Swyllys 
6773089Swyllys 
6783089Swyllys 	va_end(ap);
6793089Swyllys 	if (rc == KMFBER_DEFAULT) {
6803089Swyllys 	va_start(ap, fmt);
6813089Swyllys 	for (p--; fmt < p && *fmt; fmt++) {
682*6051Swyllys 		switch (*fmt) {
6833089Swyllys 		case 'a':	/* octet string - allocate storage as needed */
684*6051Swyllys 			ss = va_arg(ap, char **);
685*6051Swyllys 			if (ss != NULL && *ss != NULL) {
686*6051Swyllys 				free(*ss);
687*6051Swyllys 				*ss = NULL;
688*6051Swyllys 			}
689*6051Swyllys 			break;
6903089Swyllys 
6913089Swyllys 		case 'b':	/* boolean */
692*6051Swyllys 			i = va_arg(ap, int *);
693*6051Swyllys 			break;
6943089Swyllys 
6953089Swyllys 		case 'e':	/* enumerated */
6963089Swyllys 		case 'i':	/* int */
697*6051Swyllys 			l = va_arg(ap, ber_slen_t *);
698*6051Swyllys 			break;
6993089Swyllys 
7003089Swyllys 		case 'l':	/* length of next item */
701*6051Swyllys 			l = va_arg(ap, ber_slen_t *);
702*6051Swyllys 			break;
7033089Swyllys 
7043089Swyllys 		case 'n':	/* null */
705*6051Swyllys 			break;
7063089Swyllys 
7073089Swyllys 		case 's':	/* octet string - in a buffer */
708*6051Swyllys 			s = va_arg(ap, char *);
709*6051Swyllys 			l = va_arg(ap, ber_slen_t *);
710*6051Swyllys 			break;
7113089Swyllys 
7123089Swyllys 		case 'o':	/* octet string in a supplied berval */
713*6051Swyllys 			bval = va_arg(ap, struct berval *);
714*6051Swyllys 			if (bval->bv_val) free(bval->bv_val);
715*6051Swyllys 			(void) memset(bval, 0, sizeof (struct berval));
716*6051Swyllys 			break;
7173089Swyllys 
7183089Swyllys 		case 'O':	/* octet string - allocate & include length */
719*6051Swyllys 			bvp = va_arg(ap, struct berval **);
720*6051Swyllys 			kmfber_bvfree(*bvp);
721*6051Swyllys 			bvp = NULL;
722*6051Swyllys 			break;
7233089Swyllys 
7243089Swyllys 		case 'B':	/* bit string - allocate storage as needed */
725*6051Swyllys 			ss = va_arg(ap, char **);
726*6051Swyllys 			l = va_arg(ap, ber_slen_t *); /* for length, in bits */
727*6051Swyllys 			if (ss != NULL && *ss != NULL) {
728*6051Swyllys 				free(*ss);
729*6051Swyllys 				*ss = NULL;
730*6051Swyllys 			}
731*6051Swyllys 			break;
7323089Swyllys 
7333089Swyllys 		case 't':	/* tag of next item */
734*6051Swyllys 			t = va_arg(ap, ber_tag_t *);
735*6051Swyllys 			break;
7363089Swyllys 		case 'T':	/* skip tag of next item */
737*6051Swyllys 			t = va_arg(ap, ber_tag_t *);
738*6051Swyllys 			break;
7393089Swyllys 
7403089Swyllys 		case 'v':	/* sequence of strings */
741*6051Swyllys 			sss = va_arg(ap, char ***);
742*6051Swyllys 			if (sss != NULL && *sss != NULL) {
743*6051Swyllys 				ber_svecfree(*sss);
744*6051Swyllys 				*sss = NULL;
745*6051Swyllys 			}
746*6051Swyllys 			break;
7473089Swyllys 
7483089Swyllys 		case 'V':	/* sequence of strings + lengths */
749*6051Swyllys 			bv = va_arg(ap, struct berval ***);
750*6051Swyllys 			kmfber_bvecfree(*bv);
751*6051Swyllys 			*bv = NULL;
752*6051Swyllys 			break;
7533089Swyllys 
7543089Swyllys 		case 'x':	/* skip the next element - whatever it is */
755*6051Swyllys 			break;
7563089Swyllys 
7573089Swyllys 		case '{':	/* begin sequence */
7583089Swyllys 		case '[':	/* begin set */
759*6051Swyllys 			break;
7603089Swyllys 
7613089Swyllys 		case '}':	/* end sequence */
7623089Swyllys 		case ']':	/* end set */
763*6051Swyllys 			break;
7643089Swyllys 
7653089Swyllys 		default:
766*6051Swyllys 			break;
767*6051Swyllys 		}
7683089Swyllys 	} /* for */
7693089Swyllys 	va_end(ap);
7703089Swyllys 	} /* if */
7713089Swyllys 
7723089Swyllys 	return (rc);
7733089Swyllys }
7743089Swyllys 
7753089Swyllys struct berval *
7763089Swyllys kmfber_bvdup(const struct berval *bv)
7773089Swyllys {
7783089Swyllys 	struct berval	*new;
7793089Swyllys 
7803089Swyllys 	if ((new = (struct berval *)malloc(sizeof (struct berval)))
781*6051Swyllys 	    == NULL) {
7823089Swyllys 		return (NULL);
7833089Swyllys 	}
7843089Swyllys 	if (bv->bv_val == NULL) {
7853089Swyllys 		new->bv_val = NULL;
7863089Swyllys 		new->bv_len = 0;
7873089Swyllys 	} else {
7883089Swyllys 		if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
789*6051Swyllys 		    == NULL) {
790*6051Swyllys 			return (NULL);
7913089Swyllys 		}
7923089Swyllys 		(void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
7933089Swyllys 		new->bv_val[bv->bv_len] = '\0';
7943089Swyllys 		new->bv_len = bv->bv_len;
7953089Swyllys 	}
7963089Swyllys 
7973089Swyllys 	return (new);
7983089Swyllys }
799