xref: /illumos-gate/usr/src/lib/libkmf/ber_der/common/decode.c (revision e65e5c2d2f32a99e8c5f740cabae9075dab03ce7)
199ebb4caSwyllys /*
2*e65e5c2dSWyllys Ingersoll  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
399ebb4caSwyllys  * Use is subject to license terms.
499ebb4caSwyllys  */
599ebb4caSwyllys /*
699ebb4caSwyllys  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
799ebb4caSwyllys  *
899ebb4caSwyllys  * The contents of this file are subject to the Netscape Public License
999ebb4caSwyllys  * Version 1.0 (the "NPL"); you may not use this file except in
1099ebb4caSwyllys  * compliance with the NPL.  You may obtain a copy of the NPL at
1199ebb4caSwyllys  * http://www.mozilla.org/NPL/
1299ebb4caSwyllys  *
1399ebb4caSwyllys  * Software distributed under the NPL is distributed on an "AS IS" basis,
1499ebb4caSwyllys  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
1599ebb4caSwyllys  * for the specific language governing rights and limitations under the
1699ebb4caSwyllys  * NPL.
1799ebb4caSwyllys  *
1899ebb4caSwyllys  * The Initial Developer of this code under the NPL is Netscape
1999ebb4caSwyllys  * Communications Corporation.  Portions created by Netscape are
2099ebb4caSwyllys  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
2199ebb4caSwyllys  * Reserved.
2299ebb4caSwyllys  */
2399ebb4caSwyllys 
2499ebb4caSwyllys /*
2599ebb4caSwyllys  * Copyright (c) 1990 Regents of the University of Michigan.
2699ebb4caSwyllys  * All rights reserved.
2799ebb4caSwyllys  *
2899ebb4caSwyllys  * Redistribution and use in source and binary forms are permitted
2999ebb4caSwyllys  * provided that this notice is preserved and that due credit is given
3099ebb4caSwyllys  * to the University of Michigan at Ann Arbor. The name of the University
3199ebb4caSwyllys  * may not be used to endorse or promote products derived from this
3299ebb4caSwyllys  * software without specific prior written permission. This software
3399ebb4caSwyllys  * is provided ``as is'' without express or implied warranty.
3499ebb4caSwyllys  */
3599ebb4caSwyllys 
3699ebb4caSwyllys /* decode.c - ber input decoding routines */
3799ebb4caSwyllys 
3899ebb4caSwyllys #include <strings.h>
3999ebb4caSwyllys #include <sys/types.h>
4099ebb4caSwyllys #include <netinet/in.h>
4199ebb4caSwyllys #include <inttypes.h>
4299ebb4caSwyllys 
4399ebb4caSwyllys #include <ber_der.h>
4499ebb4caSwyllys #include "kmfber_int.h"
4599ebb4caSwyllys 
4699ebb4caSwyllys static void
ber_svecfree(char ** vals)4799ebb4caSwyllys ber_svecfree(char **vals)
4899ebb4caSwyllys {
4999ebb4caSwyllys 	int	i;
5099ebb4caSwyllys 
5199ebb4caSwyllys 	if (vals == NULL)
5299ebb4caSwyllys 		return;
5399ebb4caSwyllys 	for (i = 0; vals[i] != NULL; i++)
5499ebb4caSwyllys 		free(vals[i]);
5599ebb4caSwyllys 	free((char *)vals);
5699ebb4caSwyllys }
5799ebb4caSwyllys 
5899ebb4caSwyllys /*
5999ebb4caSwyllys  * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
6099ebb4caSwyllys  * If that changes, the kmfber_peek_tag() and/or
6199ebb4caSwyllys  * kmfkmfber_skip_tag() implementations will need to be changed.
6299ebb4caSwyllys  */
6399ebb4caSwyllys /* return the tag - KMFBER_DEFAULT returned means trouble */
6499ebb4caSwyllys static ber_tag_t
kmfber_get_tag(BerElement * ber)6599ebb4caSwyllys kmfber_get_tag(BerElement *ber)
6699ebb4caSwyllys {
6799ebb4caSwyllys 	unsigned char	xbyte;
6899ebb4caSwyllys 	ber_tag_t	tag;
6999ebb4caSwyllys 	char		*tagp;
7099ebb4caSwyllys 	int		i;
7199ebb4caSwyllys 
7299ebb4caSwyllys 	if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
7399ebb4caSwyllys 		return (KMFBER_DEFAULT);
7499ebb4caSwyllys 
7599ebb4caSwyllys 	if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
7699ebb4caSwyllys 		return ((ber_uint_t)xbyte);
7799ebb4caSwyllys 
7899ebb4caSwyllys 	tagp = (char *)&tag;
7999ebb4caSwyllys 	tagp[0] = xbyte;
8099ebb4caSwyllys 	for (i = 1; i < sizeof (ber_int_t); i++) {
8199ebb4caSwyllys 		if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
8299ebb4caSwyllys 			return (KMFBER_DEFAULT);
8399ebb4caSwyllys 
8499ebb4caSwyllys 		tagp[i] = xbyte;
8599ebb4caSwyllys 
8699ebb4caSwyllys 		if (! (xbyte & KMFBER_MORE_TAG_MASK))
8799ebb4caSwyllys 			break;
8899ebb4caSwyllys 	}
8999ebb4caSwyllys 
9099ebb4caSwyllys 	/* tag too big! */
9199ebb4caSwyllys 	if (i == sizeof (ber_int_t))
9299ebb4caSwyllys 		return (KMFBER_DEFAULT);
9399ebb4caSwyllys 
9499ebb4caSwyllys 	/* want leading, not trailing 0's */
9599ebb4caSwyllys 	return (tag >> (sizeof (ber_int_t)- i - 1));
9699ebb4caSwyllys }
9799ebb4caSwyllys 
9899ebb4caSwyllys /*
9999ebb4caSwyllys  * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
10099ebb4caSwyllys  * If that changes, the implementation of kmfber_peek_tag() will need to
10199ebb4caSwyllys  * be changed.
10299ebb4caSwyllys  */
10399ebb4caSwyllys ber_tag_t
kmfber_skip_tag(BerElement * ber,ber_len_t * len)10499ebb4caSwyllys kmfber_skip_tag(BerElement *ber, ber_len_t *len)
10599ebb4caSwyllys {
10699ebb4caSwyllys 	ber_tag_t	tag;
10799ebb4caSwyllys 	unsigned char	lc;
10899ebb4caSwyllys 	int		noctets, diff;
10999ebb4caSwyllys 	uint32_t	netlen;
11099ebb4caSwyllys 
11199ebb4caSwyllys 	/*
11299ebb4caSwyllys 	 * Any ber element looks like this: tag length contents.
11399ebb4caSwyllys 	 * Assuming everything's ok, we return the tag byte (we
11499ebb4caSwyllys 	 * can assume a single byte), and return the length in len.
11599ebb4caSwyllys 	 *
11699ebb4caSwyllys 	 * Assumptions:
11799ebb4caSwyllys 	 *	1) definite lengths
11899ebb4caSwyllys 	 *	2) primitive encodings used whenever possible
11999ebb4caSwyllys 	 */
12099ebb4caSwyllys 
12199ebb4caSwyllys 	/*
12299ebb4caSwyllys 	 * First, we read the tag.
12399ebb4caSwyllys 	 */
12499ebb4caSwyllys 
12599ebb4caSwyllys 	if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
12699ebb4caSwyllys 		return (KMFBER_DEFAULT);
12799ebb4caSwyllys 
12899ebb4caSwyllys 	/*
12999ebb4caSwyllys 	 * Next, read the length.  The first byte contains the length of
13099ebb4caSwyllys 	 * the length.  If bit 8 is set, the length is the long form,
13199ebb4caSwyllys 	 * otherwise it's the short form.  We don't allow a length that's
13299ebb4caSwyllys 	 * greater than what we can hold in an unsigned long.
13399ebb4caSwyllys 	 */
13499ebb4caSwyllys 
13599ebb4caSwyllys 	*len = 0;
13699ebb4caSwyllys 	netlen = 0;
13799ebb4caSwyllys 	if (kmfber_read(ber, (char *)&lc, 1) != 1)
13899ebb4caSwyllys 		return (KMFBER_DEFAULT);
13999ebb4caSwyllys 	if (lc & 0x80) {
14099ebb4caSwyllys 		noctets = (lc & 0x7f);
14199ebb4caSwyllys 		if (noctets > sizeof (ber_uint_t))
14299ebb4caSwyllys 			return (KMFBER_DEFAULT);
14399ebb4caSwyllys 		diff = sizeof (ber_int_t) - noctets;
14499ebb4caSwyllys 		if (kmfber_read(ber, (char *)&netlen + diff, noctets)
14599ebb4caSwyllys 		    != noctets)
14699ebb4caSwyllys 			return (KMFBER_DEFAULT);
14799ebb4caSwyllys 		*len = ntohl(netlen);
14899ebb4caSwyllys 	} else {
14999ebb4caSwyllys 		*len = lc;
15099ebb4caSwyllys 	}
15199ebb4caSwyllys 
15299ebb4caSwyllys 	return (tag);
15399ebb4caSwyllys }
15499ebb4caSwyllys 
15599ebb4caSwyllys 
15699ebb4caSwyllys /*
15799ebb4caSwyllys  * Note: Previously, we passed the "ber" parameter directly to
15899ebb4caSwyllys  * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
15999ebb4caSwyllys  * We now take advantage of the fact that the only ber structure
16099ebb4caSwyllys  * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
16199ebb4caSwyllys  * If that changes, this code must change too.
16299ebb4caSwyllys  */
16399ebb4caSwyllys static ber_tag_t
kmfber_peek_tag(BerElement * ber,ber_len_t * len)16499ebb4caSwyllys kmfber_peek_tag(BerElement *ber, ber_len_t *len)
16599ebb4caSwyllys {
16699ebb4caSwyllys 	BerElement	bercopy;
16799ebb4caSwyllys 
16899ebb4caSwyllys 	bercopy.ber_end = ber->ber_end;
16999ebb4caSwyllys 	bercopy.ber_ptr = ber->ber_ptr;
17099ebb4caSwyllys 	return (kmfber_skip_tag(&bercopy, len));
17199ebb4caSwyllys }
17299ebb4caSwyllys 
17399ebb4caSwyllys static int
ber_getnint(BerElement * ber,ber_int_t * num,ber_slen_t len)17499ebb4caSwyllys ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
17599ebb4caSwyllys {
17699ebb4caSwyllys 	int i;
17799ebb4caSwyllys 	ber_int_t value;
17899ebb4caSwyllys 	unsigned char buffer[sizeof (ber_int_t)];
17999ebb4caSwyllys 	/*
18099ebb4caSwyllys 	 * The tag and length have already been stripped off.  We should
18199ebb4caSwyllys 	 * be sitting right before len bytes of 2's complement integer,
18299ebb4caSwyllys 	 * ready to be read straight into an int.  We may have to sign
18399ebb4caSwyllys 	 * extend after we read it in.
18499ebb4caSwyllys 	 */
18599ebb4caSwyllys 
186ab8b4e5cSWyllys Ingersoll 	if (len > sizeof (buffer))
18799ebb4caSwyllys 		return (-1);
18899ebb4caSwyllys 
18999ebb4caSwyllys 	/* read into the low-order bytes of netnum */
19099ebb4caSwyllys 	if (kmfber_read(ber, (char *)buffer, len) != len)
19199ebb4caSwyllys 		return (-1);
19299ebb4caSwyllys 
19399ebb4caSwyllys 	/* This sets the required sign extension */
19499ebb4caSwyllys 	if (len != 0) {
19599ebb4caSwyllys 		value = 0x80 & buffer[0] ? (-1) : 0;
19699ebb4caSwyllys 	} else {
19799ebb4caSwyllys 		value = 0;
19899ebb4caSwyllys 	}
19999ebb4caSwyllys 
20099ebb4caSwyllys 	for (i = 0; i < len; i++)
20199ebb4caSwyllys 		value = (value << 8) | buffer[i];
20299ebb4caSwyllys 
20399ebb4caSwyllys 	*num = value;
20499ebb4caSwyllys 
20599ebb4caSwyllys 	return (len);
20699ebb4caSwyllys }
20799ebb4caSwyllys 
20899ebb4caSwyllys static ber_tag_t
kmfber_get_int(BerElement * ber,ber_int_t * num)20999ebb4caSwyllys kmfber_get_int(BerElement *ber, ber_int_t *num)
21099ebb4caSwyllys {
21199ebb4caSwyllys 	ber_tag_t	tag;
21299ebb4caSwyllys 	ber_len_t	len;
21399ebb4caSwyllys 
21499ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
21599ebb4caSwyllys 		return (KMFBER_DEFAULT);
21699ebb4caSwyllys 
21799ebb4caSwyllys 	/*
21899ebb4caSwyllys 	 * len is being demoted to a long here --  possible conversion error
21999ebb4caSwyllys 	 */
22099ebb4caSwyllys 
22199ebb4caSwyllys 	if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
22299ebb4caSwyllys 		return (KMFBER_DEFAULT);
22399ebb4caSwyllys 	else
22499ebb4caSwyllys 		return (tag);
22599ebb4caSwyllys }
22699ebb4caSwyllys 
22799ebb4caSwyllys static ber_tag_t
kmfber_get_stringb(BerElement * ber,char * buf,ber_len_t * len)22899ebb4caSwyllys kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
22999ebb4caSwyllys {
23099ebb4caSwyllys 	ber_len_t	datalen;
23199ebb4caSwyllys 	ber_tag_t	tag;
23299ebb4caSwyllys #ifdef STR_TRANSLATION
23399ebb4caSwyllys 	char		*transbuf;
23499ebb4caSwyllys #endif /* STR_TRANSLATION */
23599ebb4caSwyllys 
23699ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
23799ebb4caSwyllys 		return (KMFBER_DEFAULT);
23899ebb4caSwyllys 	if (datalen > (*len - 1))
23999ebb4caSwyllys 		return (KMFBER_DEFAULT);
24099ebb4caSwyllys 
24199ebb4caSwyllys 	/*
24299ebb4caSwyllys 	 * datalen is being demoted to a long here --  possible conversion error
24399ebb4caSwyllys 	 */
24499ebb4caSwyllys 
24599ebb4caSwyllys 	if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
24699ebb4caSwyllys 		return (KMFBER_DEFAULT);
24799ebb4caSwyllys 
24899ebb4caSwyllys 	buf[datalen] = '\0';
24999ebb4caSwyllys 
25099ebb4caSwyllys #ifdef STR_TRANSLATION
25199ebb4caSwyllys 	if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
25299ebb4caSwyllys 	    != 0 && ber->ber_decode_translate_proc != NULL) {
25399ebb4caSwyllys 
25499ebb4caSwyllys 		transbuf = buf;
25599ebb4caSwyllys 		++datalen;
25699ebb4caSwyllys 		if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
25799ebb4caSwyllys 		    0) != 0) {
25899ebb4caSwyllys 			return (KMFBER_DEFAULT);
25999ebb4caSwyllys 		}
26099ebb4caSwyllys 		if (datalen > *len) {
26199ebb4caSwyllys 			free(transbuf);
26299ebb4caSwyllys 			return (KMFBER_DEFAULT);
26399ebb4caSwyllys 		}
26499ebb4caSwyllys 		(void) memmove(buf, transbuf, datalen);
26599ebb4caSwyllys 		free(transbuf);
26699ebb4caSwyllys 		--datalen;
26799ebb4caSwyllys 	}
26899ebb4caSwyllys #endif /* STR_TRANSLATION */
26999ebb4caSwyllys 
27099ebb4caSwyllys 	*len = datalen;
27199ebb4caSwyllys 	return (tag);
27299ebb4caSwyllys }
27399ebb4caSwyllys 
27499ebb4caSwyllys static ber_tag_t
kmfber_get_stringa(BerElement * ber,char ** buf)27599ebb4caSwyllys kmfber_get_stringa(BerElement *ber, char **buf)
27699ebb4caSwyllys {
27799ebb4caSwyllys 	ber_len_t	datalen;
27899ebb4caSwyllys 	ber_tag_t	tag;
27999ebb4caSwyllys 
28099ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
28199ebb4caSwyllys 		return (KMFBER_DEFAULT);
28299ebb4caSwyllys 
28399ebb4caSwyllys 	if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
28499ebb4caSwyllys 		return (KMFBER_DEFAULT);
28599ebb4caSwyllys 
28699ebb4caSwyllys 	/*
28799ebb4caSwyllys 	 * datalen is being demoted to a long here --  possible conversion error
28899ebb4caSwyllys 	 */
28999ebb4caSwyllys 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
29099ebb4caSwyllys 		return (KMFBER_DEFAULT);
29199ebb4caSwyllys 	(*buf)[datalen] = '\0';
29299ebb4caSwyllys 
29399ebb4caSwyllys 	return (tag);
29499ebb4caSwyllys }
29599ebb4caSwyllys 
29699ebb4caSwyllys ber_tag_t
ber_get_oid(BerElement * ber,struct berval * oid)29799ebb4caSwyllys ber_get_oid(BerElement *ber, struct berval *oid)
29899ebb4caSwyllys {
29999ebb4caSwyllys 	ber_len_t	len;
30099ebb4caSwyllys 	ber_tag_t	tag;
30199ebb4caSwyllys 
30299ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
30399ebb4caSwyllys 		return (KMFBER_DEFAULT);
30499ebb4caSwyllys 	}
30599ebb4caSwyllys 
30699ebb4caSwyllys 	if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
30799ebb4caSwyllys 		return (KMFBER_DEFAULT);
30899ebb4caSwyllys 	}
30999ebb4caSwyllys 	oid->bv_len = len;
31099ebb4caSwyllys 
31199ebb4caSwyllys 	if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
31299ebb4caSwyllys 	    (ber_slen_t)oid->bv_len)
31399ebb4caSwyllys 		return (KMFBER_DEFAULT);
31499ebb4caSwyllys 
31599ebb4caSwyllys 	return (tag);
31699ebb4caSwyllys }
31799ebb4caSwyllys 
31899ebb4caSwyllys ber_tag_t
ber_get_bigint(BerElement * ber,struct berval ** bv)31999ebb4caSwyllys ber_get_bigint(BerElement *ber, struct berval **bv)
32099ebb4caSwyllys {
32199ebb4caSwyllys 	ber_len_t	len;
32299ebb4caSwyllys 	ber_tag_t	tag;
32399ebb4caSwyllys 
32499ebb4caSwyllys 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
32599ebb4caSwyllys 	    == NULL) {
32699ebb4caSwyllys 		return (KMFBER_DEFAULT);
32799ebb4caSwyllys 	}
328d00756ccSwyllys 	(*bv)->bv_len = 0;
329d00756ccSwyllys 	(*bv)->bv_val = NULL;
33099ebb4caSwyllys 
33199ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
33299ebb4caSwyllys 		return (KMFBER_DEFAULT);
33399ebb4caSwyllys 	}
33499ebb4caSwyllys 
33599ebb4caSwyllys 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
33699ebb4caSwyllys 	    == NULL) {
33799ebb4caSwyllys 		return (KMFBER_DEFAULT);
33899ebb4caSwyllys 	}
33999ebb4caSwyllys 
34099ebb4caSwyllys 	/*
34199ebb4caSwyllys 	 * len is being demoted to a long here --  possible conversion error
34299ebb4caSwyllys 	 */
34399ebb4caSwyllys 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
34499ebb4caSwyllys 		return (KMFBER_DEFAULT);
34599ebb4caSwyllys 
34699ebb4caSwyllys 	(*bv)->bv_len = len;
34799ebb4caSwyllys 
348*e65e5c2dSWyllys Ingersoll 	/* If DER encoding, strip leading 0's if high-order bit is set */
34999ebb4caSwyllys 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
35099ebb4caSwyllys 		char *p = (*bv)->bv_val;
351*e65e5c2dSWyllys Ingersoll 		while ((*p == 0x00) && ((*bv)->bv_len > 0) && (p[1] & 0x80)) {
35299ebb4caSwyllys 			p++;
35399ebb4caSwyllys 			(*bv)->bv_len--;
35499ebb4caSwyllys 		}
35599ebb4caSwyllys 		/*
35699ebb4caSwyllys 		 * Shift the buffer to the beginning of the allocated space
35799ebb4caSwyllys 		 * so it can be properly freed later.
35899ebb4caSwyllys 		 */
35999ebb4caSwyllys 		if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
36099ebb4caSwyllys 			(void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
36199ebb4caSwyllys 	}
36299ebb4caSwyllys 
36399ebb4caSwyllys 	return (tag);
36499ebb4caSwyllys }
36599ebb4caSwyllys 
36699ebb4caSwyllys static ber_tag_t
kmfber_get_stringal(BerElement * ber,struct berval ** bv)36799ebb4caSwyllys kmfber_get_stringal(BerElement *ber, struct berval **bv)
36899ebb4caSwyllys {
36999ebb4caSwyllys 	ber_len_t	len;
37099ebb4caSwyllys 	ber_tag_t	tag;
37199ebb4caSwyllys 
37299ebb4caSwyllys 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
37399ebb4caSwyllys 	    == NULL) {
37499ebb4caSwyllys 		return (KMFBER_DEFAULT);
37599ebb4caSwyllys 	}
37699ebb4caSwyllys 
37799ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
37899ebb4caSwyllys 		return (KMFBER_DEFAULT);
37999ebb4caSwyllys 	}
38099ebb4caSwyllys 
38199ebb4caSwyllys 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
38299ebb4caSwyllys 	    == NULL) {
38399ebb4caSwyllys 		return (KMFBER_DEFAULT);
38499ebb4caSwyllys 	}
38599ebb4caSwyllys 
38699ebb4caSwyllys 	/*
38799ebb4caSwyllys 	 * len is being demoted to a long here --  possible conversion error
38899ebb4caSwyllys 	 */
38999ebb4caSwyllys 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
39099ebb4caSwyllys 		return (KMFBER_DEFAULT);
39199ebb4caSwyllys 	((*bv)->bv_val)[len] = '\0';
39299ebb4caSwyllys 	(*bv)->bv_len = len;
39399ebb4caSwyllys 
39499ebb4caSwyllys 	return (tag);
39599ebb4caSwyllys }
39699ebb4caSwyllys 
39799ebb4caSwyllys static ber_tag_t
kmfber_get_bitstringa(BerElement * ber,char ** buf,ber_len_t * blen)39899ebb4caSwyllys kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
39999ebb4caSwyllys {
40099ebb4caSwyllys 	ber_len_t	datalen;
40199ebb4caSwyllys 	ber_tag_t	tag;
40299ebb4caSwyllys 	unsigned char	unusedbits;
40399ebb4caSwyllys 
40499ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
40599ebb4caSwyllys 		return (KMFBER_DEFAULT);
40699ebb4caSwyllys 
40799ebb4caSwyllys 	if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
40899ebb4caSwyllys 		return (KMFBER_DEFAULT);
40999ebb4caSwyllys 
41099ebb4caSwyllys 	if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
41199ebb4caSwyllys 		return (KMFBER_DEFAULT);
41299ebb4caSwyllys 
41399ebb4caSwyllys 	/* Subtract 1 for the unused bits */
41499ebb4caSwyllys 	datalen--;
41599ebb4caSwyllys 
41699ebb4caSwyllys 	/*
41799ebb4caSwyllys 	 * datalen is being demoted to a long here --  possible conversion error
41899ebb4caSwyllys 	 */
41999ebb4caSwyllys 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
42099ebb4caSwyllys 		return (KMFBER_DEFAULT);
42199ebb4caSwyllys 
42299ebb4caSwyllys 	*blen = datalen * 8 - unusedbits;
42399ebb4caSwyllys 	return (tag);
42499ebb4caSwyllys }
42599ebb4caSwyllys 
42699ebb4caSwyllys static ber_tag_t
kmfber_get_null(BerElement * ber)42799ebb4caSwyllys kmfber_get_null(BerElement *ber)
42899ebb4caSwyllys {
42999ebb4caSwyllys 	ber_len_t	len;
43099ebb4caSwyllys 	ber_tag_t tag;
43199ebb4caSwyllys 
43299ebb4caSwyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
43399ebb4caSwyllys 		return (KMFBER_DEFAULT);
43499ebb4caSwyllys 
43599ebb4caSwyllys 	if (len != 0)
43699ebb4caSwyllys 		return (KMFBER_DEFAULT);
43799ebb4caSwyllys 
43899ebb4caSwyllys 	return (tag);
43999ebb4caSwyllys }
44099ebb4caSwyllys 
44199ebb4caSwyllys static ber_tag_t
kmfber_get_boolean(BerElement * ber,int * boolval)44299ebb4caSwyllys kmfber_get_boolean(BerElement *ber, int *boolval)
44399ebb4caSwyllys {
44499ebb4caSwyllys 	ber_int_t	longbool;
44599ebb4caSwyllys 	int		rc;
44699ebb4caSwyllys 
44799ebb4caSwyllys 	rc = kmfber_get_int(ber, &longbool);
44899ebb4caSwyllys 	*boolval = longbool;
44999ebb4caSwyllys 
45099ebb4caSwyllys 	return (rc);
45199ebb4caSwyllys }
45299ebb4caSwyllys 
45399ebb4caSwyllys ber_tag_t
kmfber_first_element(BerElement * ber,ber_len_t * len,char ** last)45499ebb4caSwyllys kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
45599ebb4caSwyllys {
45699ebb4caSwyllys 	/* skip the sequence header, use the len to mark where to stop */
45799ebb4caSwyllys 	if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
45899ebb4caSwyllys 		return (KMFBER_ERROR);
45999ebb4caSwyllys 	}
46099ebb4caSwyllys 
46199ebb4caSwyllys 	*last = ber->ber_ptr + *len;
46299ebb4caSwyllys 
46399ebb4caSwyllys 	if (*last == ber->ber_ptr) {
46499ebb4caSwyllys 		return (KMFBER_END_OF_SEQORSET);
46599ebb4caSwyllys 	}
46699ebb4caSwyllys 
46799ebb4caSwyllys 	return (kmfber_peek_tag(ber, len));
46899ebb4caSwyllys }
46999ebb4caSwyllys 
47099ebb4caSwyllys ber_tag_t
kmfber_next_element(BerElement * ber,ber_len_t * len,char * last)47199ebb4caSwyllys kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
47299ebb4caSwyllys {
47399ebb4caSwyllys 	if (ber->ber_ptr == last) {
47499ebb4caSwyllys 		return (KMFBER_END_OF_SEQORSET);
47599ebb4caSwyllys 	}
47699ebb4caSwyllys 
47799ebb4caSwyllys 	return (kmfber_peek_tag(ber, len));
47899ebb4caSwyllys }
47999ebb4caSwyllys 
48099ebb4caSwyllys void
kmfber_bvfree(struct berval * bv)48199ebb4caSwyllys kmfber_bvfree(struct berval *bv)
48299ebb4caSwyllys {
48399ebb4caSwyllys 	if (bv != NULL) {
48499ebb4caSwyllys 		if (bv->bv_val != NULL) {
48599ebb4caSwyllys 			free(bv->bv_val);
48699ebb4caSwyllys 		}
48799ebb4caSwyllys 		free((char *)bv);
48899ebb4caSwyllys 	}
48999ebb4caSwyllys }
49099ebb4caSwyllys 
49199ebb4caSwyllys void
kmfber_bvecfree(struct berval ** bv)49299ebb4caSwyllys kmfber_bvecfree(struct berval **bv)
49399ebb4caSwyllys {
49499ebb4caSwyllys 	int	i;
49599ebb4caSwyllys 
49699ebb4caSwyllys 	if (bv != NULL) {
49799ebb4caSwyllys 		for (i = 0; bv[i] != NULL; i++) {
49899ebb4caSwyllys 			kmfber_bvfree(bv[i]);
49999ebb4caSwyllys 		}
50099ebb4caSwyllys 		free((char *)bv);
50199ebb4caSwyllys 	}
50299ebb4caSwyllys }
50399ebb4caSwyllys 
50499ebb4caSwyllys /* VARARGS */
50599ebb4caSwyllys ber_tag_t
kmfber_scanf(BerElement * ber,const char * fmt,...)50699ebb4caSwyllys kmfber_scanf(BerElement *ber, const char *fmt, ...)
50799ebb4caSwyllys {
50899ebb4caSwyllys 	va_list		ap;
50999ebb4caSwyllys 	char		*last, *p;
51099ebb4caSwyllys 	char		*s, **ss, ***sss;
51199ebb4caSwyllys 	struct berval 	***bv, **bvp, *bval;
51299ebb4caSwyllys 	int		*i, j;
51399ebb4caSwyllys 	ber_slen_t	*l;
51499ebb4caSwyllys 	ber_int_t	rc, tag, *b_int;
51599ebb4caSwyllys 	ber_tag_t	*t;
51699ebb4caSwyllys 	ber_len_t	len;
51799ebb4caSwyllys 	size_t		array_size;
51899ebb4caSwyllys 
51999ebb4caSwyllys 	va_start(ap, fmt);
52099ebb4caSwyllys 
52199ebb4caSwyllys 	for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
52299ebb4caSwyllys 	switch (*p) {
52399ebb4caSwyllys 		case 'a':	/* octet string - allocate storage as needed */
52499ebb4caSwyllys 		ss = va_arg(ap, char **);
52599ebb4caSwyllys 		rc = kmfber_get_stringa(ber, ss);
52699ebb4caSwyllys 		break;
52799ebb4caSwyllys 
52899ebb4caSwyllys 		case 'b':	/* boolean */
52999ebb4caSwyllys 		i = va_arg(ap, int *);
53099ebb4caSwyllys 		rc = kmfber_get_boolean(ber, i);
53199ebb4caSwyllys 		break;
53299ebb4caSwyllys 
53399ebb4caSwyllys 		case 'D':	/* Object ID */
53499ebb4caSwyllys 		bval = va_arg(ap, struct berval *);
53599ebb4caSwyllys 		rc = ber_get_oid(ber, bval);
53699ebb4caSwyllys 		break;
53799ebb4caSwyllys 		case 'e':	/* enumerated */
53899ebb4caSwyllys 		case 'i':	/* int */
53999ebb4caSwyllys 		b_int = va_arg(ap, ber_int_t *);
54099ebb4caSwyllys 		rc = kmfber_get_int(ber, b_int);
54199ebb4caSwyllys 		break;
54299ebb4caSwyllys 
54399ebb4caSwyllys 		case 'l':	/* length of next item */
54499ebb4caSwyllys 		l = va_arg(ap, ber_slen_t *);
54599ebb4caSwyllys 		rc = kmfber_peek_tag(ber, (ber_len_t *)l);
54699ebb4caSwyllys 		break;
54799ebb4caSwyllys 
54899ebb4caSwyllys 		case 'n':	/* null */
54999ebb4caSwyllys 		rc = kmfber_get_null(ber);
55099ebb4caSwyllys 		break;
55199ebb4caSwyllys 
55299ebb4caSwyllys 		case 's':	/* octet string - in a buffer */
55399ebb4caSwyllys 		s = va_arg(ap, char *);
55499ebb4caSwyllys 		l = va_arg(ap, ber_slen_t *);
55599ebb4caSwyllys 		rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
55699ebb4caSwyllys 		break;
55799ebb4caSwyllys 
55899ebb4caSwyllys 		case 'o':	/* octet string in a supplied berval */
55999ebb4caSwyllys 		bval = va_arg(ap, struct berval *);
56099ebb4caSwyllys 		(void) kmfber_peek_tag(ber, &bval->bv_len);
56199ebb4caSwyllys 		rc = kmfber_get_stringa(ber, &bval->bv_val);
56299ebb4caSwyllys 		break;
56399ebb4caSwyllys 
56499ebb4caSwyllys 		case 'I': /* variable length Integer */
56599ebb4caSwyllys 		/* Treat INTEGER same as an OCTET string, but ignore the tag */
56699ebb4caSwyllys 		bvp = va_arg(ap, struct berval **);
56799ebb4caSwyllys 		rc = ber_get_bigint(ber, bvp);
56899ebb4caSwyllys 		break;
56999ebb4caSwyllys 		case 'O': /* octet string - allocate & include length */
57099ebb4caSwyllys 		bvp = va_arg(ap, struct berval **);
57199ebb4caSwyllys 		rc = kmfber_get_stringal(ber, bvp);
57299ebb4caSwyllys 		break;
57399ebb4caSwyllys 
57499ebb4caSwyllys 		case 'B':	/* bit string - allocate storage as needed */
57599ebb4caSwyllys 		ss = va_arg(ap, char **);
57699ebb4caSwyllys 		l = va_arg(ap, ber_slen_t *); /* for length, in bits */
57799ebb4caSwyllys 		rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
57899ebb4caSwyllys 		break;
57999ebb4caSwyllys 
58099ebb4caSwyllys 		case 't':	/* tag of next item */
58199ebb4caSwyllys 		t = va_arg(ap, ber_tag_t *);
58299ebb4caSwyllys 		*t = kmfber_peek_tag(ber, &len);
58399ebb4caSwyllys 		rc = (ber_int_t)(*t);
58499ebb4caSwyllys 		break;
58599ebb4caSwyllys 
58699ebb4caSwyllys 		case 'T':	/* skip tag of next item */
58799ebb4caSwyllys 		t = va_arg(ap, ber_tag_t *);
58899ebb4caSwyllys 		*t = kmfber_skip_tag(ber, &len);
58999ebb4caSwyllys 		rc = (ber_int_t)(*t);
59099ebb4caSwyllys 		break;
59199ebb4caSwyllys 
59299ebb4caSwyllys 		case 'v':	/* sequence of strings */
59399ebb4caSwyllys 		sss = va_arg(ap, char ***);
594d00756ccSwyllys 		if (sss == NULL)
595d00756ccSwyllys 			break;
59699ebb4caSwyllys 		*sss = NULL;
59799ebb4caSwyllys 		j = 0;
59899ebb4caSwyllys 		array_size = 0;
59999ebb4caSwyllys 		for (tag = kmfber_first_element(ber, &len, &last);
60099ebb4caSwyllys 		    (tag != KMFBER_DEFAULT &&
60199ebb4caSwyllys 		    tag != KMFBER_END_OF_SEQORSET &&
60299ebb4caSwyllys 		    rc != KMFBER_DEFAULT);
60399ebb4caSwyllys 		    tag = kmfber_next_element(ber, &len, last)) {
60499ebb4caSwyllys 			if (*sss == NULL) {
60599ebb4caSwyllys 				/* Make room for at least 15 strings */
60699ebb4caSwyllys 				*sss = (char **)malloc(16 * sizeof (char *));
60799ebb4caSwyllys 				array_size = 16;
60899ebb4caSwyllys 			} else {
60999ebb4caSwyllys 				if ((size_t)(j+2) > array_size) {
61099ebb4caSwyllys 					/* We'v overflowed our buffer */
61199ebb4caSwyllys 					*sss = (char **)realloc(*sss,
61299ebb4caSwyllys 					    (array_size * 2) * sizeof (char *));
61399ebb4caSwyllys 					array_size = array_size * 2;
61499ebb4caSwyllys 				}
61599ebb4caSwyllys 			}
61699ebb4caSwyllys 			rc = kmfber_get_stringa(ber, &((*sss)[j]));
61799ebb4caSwyllys 			j++;
61899ebb4caSwyllys 		}
619d00756ccSwyllys 		if (rc != KMFBER_DEFAULT && tag != KMFBER_END_OF_SEQORSET) {
62099ebb4caSwyllys 			rc = KMFBER_DEFAULT;
62199ebb4caSwyllys 		}
62299ebb4caSwyllys 		if (j > 0)
62399ebb4caSwyllys 			(*sss)[j] = NULL;
62499ebb4caSwyllys 		break;
62599ebb4caSwyllys 
62699ebb4caSwyllys 		case 'V':	/* sequence of strings + lengths */
62799ebb4caSwyllys 		bv = va_arg(ap, struct berval ***);
62899ebb4caSwyllys 		*bv = NULL;
62999ebb4caSwyllys 		j = 0;
63099ebb4caSwyllys 		for (tag = kmfber_first_element(ber, &len, &last);
63199ebb4caSwyllys 		    (tag != KMFBER_DEFAULT &&
63299ebb4caSwyllys 		    tag != KMFBER_END_OF_SEQORSET &&
63399ebb4caSwyllys 		    rc != KMFBER_DEFAULT);
63499ebb4caSwyllys 		    tag = kmfber_next_element(ber, &len, last)) {
63599ebb4caSwyllys 			if (*bv == NULL) {
63699ebb4caSwyllys 				*bv = (struct berval **)malloc(
63799ebb4caSwyllys 				    2 * sizeof (struct berval *));
63899ebb4caSwyllys 			} else {
63999ebb4caSwyllys 				*bv = (struct berval **)realloc(*bv,
64099ebb4caSwyllys 				    (j + 2) * sizeof (struct berval *));
64199ebb4caSwyllys 			}
64299ebb4caSwyllys 			rc = kmfber_get_stringal(ber, &((*bv)[j]));
64399ebb4caSwyllys 			j++;
64499ebb4caSwyllys 		}
64599ebb4caSwyllys 		if (rc != KMFBER_DEFAULT &&
64699ebb4caSwyllys 		    tag != KMFBER_END_OF_SEQORSET) {
64799ebb4caSwyllys 			rc = KMFBER_DEFAULT;
64899ebb4caSwyllys 		}
64999ebb4caSwyllys 		if (j > 0)
65099ebb4caSwyllys 			(*bv)[j] = NULL;
65199ebb4caSwyllys 		break;
65299ebb4caSwyllys 
65399ebb4caSwyllys 		case 'x':	/* skip the next element - whatever it is */
65499ebb4caSwyllys 		if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
65599ebb4caSwyllys 			break;
65699ebb4caSwyllys 		ber->ber_ptr += len;
65799ebb4caSwyllys 		break;
65899ebb4caSwyllys 
65999ebb4caSwyllys 		case '{':	/* begin sequence */
66099ebb4caSwyllys 		case '[':	/* begin set */
66199ebb4caSwyllys 		if (*(p + 1) != 'v' && *(p + 1) != 'V')
66299ebb4caSwyllys 			rc = kmfber_skip_tag(ber, &len);
66399ebb4caSwyllys 		break;
66499ebb4caSwyllys 
66599ebb4caSwyllys 		case '}':	/* end sequence */
66699ebb4caSwyllys 		case ']':	/* end set */
66799ebb4caSwyllys 		break;
66899ebb4caSwyllys 
66999ebb4caSwyllys 		default:
67099ebb4caSwyllys 		rc = KMFBER_DEFAULT;
67199ebb4caSwyllys 		break;
67299ebb4caSwyllys 		}
67399ebb4caSwyllys 	}
67499ebb4caSwyllys 
67599ebb4caSwyllys 
67699ebb4caSwyllys 	va_end(ap);
67799ebb4caSwyllys 	if (rc == KMFBER_DEFAULT) {
67899ebb4caSwyllys 	va_start(ap, fmt);
67999ebb4caSwyllys 	for (p--; fmt < p && *fmt; fmt++) {
68099ebb4caSwyllys 		switch (*fmt) {
68199ebb4caSwyllys 		case 'a':	/* octet string - allocate storage as needed */
68299ebb4caSwyllys 			ss = va_arg(ap, char **);
683d00756ccSwyllys 			if (ss != NULL && *ss != NULL) {
68499ebb4caSwyllys 				free(*ss);
68599ebb4caSwyllys 				*ss = NULL;
686d00756ccSwyllys 			}
68799ebb4caSwyllys 			break;
68899ebb4caSwyllys 
68999ebb4caSwyllys 		case 'b':	/* boolean */
69099ebb4caSwyllys 			i = va_arg(ap, int *);
69199ebb4caSwyllys 			break;
69299ebb4caSwyllys 
69399ebb4caSwyllys 		case 'e':	/* enumerated */
69499ebb4caSwyllys 		case 'i':	/* int */
69599ebb4caSwyllys 			l = va_arg(ap, ber_slen_t *);
69699ebb4caSwyllys 			break;
69799ebb4caSwyllys 
69899ebb4caSwyllys 		case 'l':	/* length of next item */
69999ebb4caSwyllys 			l = va_arg(ap, ber_slen_t *);
70099ebb4caSwyllys 			break;
70199ebb4caSwyllys 
70299ebb4caSwyllys 		case 'n':	/* null */
70399ebb4caSwyllys 			break;
70499ebb4caSwyllys 
70599ebb4caSwyllys 		case 's':	/* octet string - in a buffer */
70699ebb4caSwyllys 			s = va_arg(ap, char *);
70799ebb4caSwyllys 			l = va_arg(ap, ber_slen_t *);
70899ebb4caSwyllys 			break;
70999ebb4caSwyllys 
71099ebb4caSwyllys 		case 'o':	/* octet string in a supplied berval */
71199ebb4caSwyllys 			bval = va_arg(ap, struct berval *);
71299ebb4caSwyllys 			if (bval->bv_val) free(bval->bv_val);
71399ebb4caSwyllys 			(void) memset(bval, 0, sizeof (struct berval));
71499ebb4caSwyllys 			break;
71599ebb4caSwyllys 
71699ebb4caSwyllys 		case 'O':	/* octet string - allocate & include length */
71799ebb4caSwyllys 			bvp = va_arg(ap, struct berval **);
71899ebb4caSwyllys 			kmfber_bvfree(*bvp);
71999ebb4caSwyllys 			bvp = NULL;
72099ebb4caSwyllys 			break;
72199ebb4caSwyllys 
72299ebb4caSwyllys 		case 'B':	/* bit string - allocate storage as needed */
72399ebb4caSwyllys 			ss = va_arg(ap, char **);
72499ebb4caSwyllys 			l = va_arg(ap, ber_slen_t *); /* for length, in bits */
725d00756ccSwyllys 			if (ss != NULL && *ss != NULL) {
726d00756ccSwyllys 				free(*ss);
72799ebb4caSwyllys 				*ss = NULL;
728d00756ccSwyllys 			}
72999ebb4caSwyllys 			break;
73099ebb4caSwyllys 
73199ebb4caSwyllys 		case 't':	/* tag of next item */
73299ebb4caSwyllys 			t = va_arg(ap, ber_tag_t *);
73399ebb4caSwyllys 			break;
73499ebb4caSwyllys 		case 'T':	/* skip tag of next item */
73599ebb4caSwyllys 			t = va_arg(ap, ber_tag_t *);
73699ebb4caSwyllys 			break;
73799ebb4caSwyllys 
73899ebb4caSwyllys 		case 'v':	/* sequence of strings */
73999ebb4caSwyllys 			sss = va_arg(ap, char ***);
740d00756ccSwyllys 			if (sss != NULL && *sss != NULL) {
74199ebb4caSwyllys 				ber_svecfree(*sss);
74299ebb4caSwyllys 				*sss = NULL;
743d00756ccSwyllys 			}
74499ebb4caSwyllys 			break;
74599ebb4caSwyllys 
74699ebb4caSwyllys 		case 'V':	/* sequence of strings + lengths */
74799ebb4caSwyllys 			bv = va_arg(ap, struct berval ***);
74899ebb4caSwyllys 			kmfber_bvecfree(*bv);
74999ebb4caSwyllys 			*bv = NULL;
75099ebb4caSwyllys 			break;
75199ebb4caSwyllys 
75299ebb4caSwyllys 		case 'x':	/* skip the next element - whatever it is */
75399ebb4caSwyllys 			break;
75499ebb4caSwyllys 
75599ebb4caSwyllys 		case '{':	/* begin sequence */
75699ebb4caSwyllys 		case '[':	/* begin set */
75799ebb4caSwyllys 			break;
75899ebb4caSwyllys 
75999ebb4caSwyllys 		case '}':	/* end sequence */
76099ebb4caSwyllys 		case ']':	/* end set */
76199ebb4caSwyllys 			break;
76299ebb4caSwyllys 
76399ebb4caSwyllys 		default:
76499ebb4caSwyllys 			break;
76599ebb4caSwyllys 		}
76699ebb4caSwyllys 	} /* for */
76799ebb4caSwyllys 	va_end(ap);
76899ebb4caSwyllys 	} /* if */
76999ebb4caSwyllys 
77099ebb4caSwyllys 	return (rc);
77199ebb4caSwyllys }
77299ebb4caSwyllys 
77399ebb4caSwyllys struct berval *
kmfber_bvdup(const struct berval * bv)77499ebb4caSwyllys kmfber_bvdup(const struct berval *bv)
77599ebb4caSwyllys {
77699ebb4caSwyllys 	struct berval	*new;
77799ebb4caSwyllys 
77899ebb4caSwyllys 	if ((new = (struct berval *)malloc(sizeof (struct berval)))
77999ebb4caSwyllys 	    == NULL) {
78099ebb4caSwyllys 		return (NULL);
78199ebb4caSwyllys 	}
78299ebb4caSwyllys 	if (bv->bv_val == NULL) {
78399ebb4caSwyllys 		new->bv_val = NULL;
78499ebb4caSwyllys 		new->bv_len = 0;
78599ebb4caSwyllys 	} else {
78699ebb4caSwyllys 		if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
78799ebb4caSwyllys 		    == NULL) {
78899ebb4caSwyllys 			return (NULL);
78999ebb4caSwyllys 		}
79099ebb4caSwyllys 		(void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
79199ebb4caSwyllys 		new->bv_val[bv->bv_len] = '\0';
79299ebb4caSwyllys 		new->bv_len = bv->bv_len;
79399ebb4caSwyllys 	}
79499ebb4caSwyllys 
79599ebb4caSwyllys 	return (new);
79699ebb4caSwyllys }
797