13089Swyllys /*
2*11973Swyllys.ingersoll@sun.com * Copyright 2010 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 #include <strings.h>
393089Swyllys #include <sys/types.h>
403089Swyllys #include <netinet/in.h>
413089Swyllys #include <inttypes.h>
423089Swyllys
433089Swyllys #include <ber_der.h>
443089Swyllys #include "kmfber_int.h"
453089Swyllys
463089Swyllys static void
ber_svecfree(char ** vals)473089Swyllys ber_svecfree(char **vals)
483089Swyllys {
493089Swyllys int i;
503089Swyllys
513089Swyllys if (vals == NULL)
523089Swyllys return;
533089Swyllys for (i = 0; vals[i] != NULL; i++)
543089Swyllys free(vals[i]);
553089Swyllys free((char *)vals);
563089Swyllys }
573089Swyllys
583089Swyllys /*
593089Swyllys * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
603089Swyllys * If that changes, the kmfber_peek_tag() and/or
613089Swyllys * kmfkmfber_skip_tag() implementations will need to be changed.
623089Swyllys */
633089Swyllys /* return the tag - KMFBER_DEFAULT returned means trouble */
643089Swyllys static ber_tag_t
kmfber_get_tag(BerElement * ber)653089Swyllys kmfber_get_tag(BerElement *ber)
663089Swyllys {
673089Swyllys unsigned char xbyte;
683089Swyllys ber_tag_t tag;
693089Swyllys char *tagp;
703089Swyllys int i;
713089Swyllys
723089Swyllys if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
733089Swyllys return (KMFBER_DEFAULT);
743089Swyllys
753089Swyllys if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
763089Swyllys return ((ber_uint_t)xbyte);
773089Swyllys
783089Swyllys tagp = (char *)&tag;
793089Swyllys tagp[0] = xbyte;
803089Swyllys for (i = 1; i < sizeof (ber_int_t); i++) {
813089Swyllys if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
823089Swyllys return (KMFBER_DEFAULT);
833089Swyllys
843089Swyllys tagp[i] = xbyte;
853089Swyllys
863089Swyllys if (! (xbyte & KMFBER_MORE_TAG_MASK))
873089Swyllys break;
883089Swyllys }
893089Swyllys
903089Swyllys /* tag too big! */
913089Swyllys if (i == sizeof (ber_int_t))
923089Swyllys return (KMFBER_DEFAULT);
933089Swyllys
943089Swyllys /* want leading, not trailing 0's */
953089Swyllys return (tag >> (sizeof (ber_int_t)- i - 1));
963089Swyllys }
973089Swyllys
983089Swyllys /*
993089Swyllys * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
1003089Swyllys * If that changes, the implementation of kmfber_peek_tag() will need to
1013089Swyllys * be changed.
1023089Swyllys */
1033089Swyllys ber_tag_t
kmfber_skip_tag(BerElement * ber,ber_len_t * len)1043089Swyllys kmfber_skip_tag(BerElement *ber, ber_len_t *len)
1053089Swyllys {
1063089Swyllys ber_tag_t tag;
1073089Swyllys unsigned char lc;
1083089Swyllys int noctets, diff;
1093089Swyllys uint32_t netlen;
1103089Swyllys
1113089Swyllys /*
1123089Swyllys * Any ber element looks like this: tag length contents.
1133089Swyllys * Assuming everything's ok, we return the tag byte (we
1143089Swyllys * can assume a single byte), and return the length in len.
1153089Swyllys *
1163089Swyllys * Assumptions:
1173089Swyllys * 1) definite lengths
1183089Swyllys * 2) primitive encodings used whenever possible
1193089Swyllys */
1203089Swyllys
1213089Swyllys /*
1223089Swyllys * First, we read the tag.
1233089Swyllys */
1243089Swyllys
1253089Swyllys if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
1263089Swyllys return (KMFBER_DEFAULT);
1273089Swyllys
1283089Swyllys /*
1293089Swyllys * Next, read the length. The first byte contains the length of
1303089Swyllys * the length. If bit 8 is set, the length is the long form,
1313089Swyllys * otherwise it's the short form. We don't allow a length that's
1323089Swyllys * greater than what we can hold in an unsigned long.
1333089Swyllys */
1343089Swyllys
1353089Swyllys *len = 0;
1363089Swyllys netlen = 0;
1373089Swyllys if (kmfber_read(ber, (char *)&lc, 1) != 1)
1383089Swyllys return (KMFBER_DEFAULT);
1393089Swyllys if (lc & 0x80) {
1403089Swyllys noctets = (lc & 0x7f);
1413089Swyllys if (noctets > sizeof (ber_uint_t))
1423089Swyllys return (KMFBER_DEFAULT);
1433089Swyllys diff = sizeof (ber_int_t) - noctets;
1443089Swyllys if (kmfber_read(ber, (char *)&netlen + diff, noctets)
1456051Swyllys != noctets)
1463089Swyllys return (KMFBER_DEFAULT);
1473089Swyllys *len = ntohl(netlen);
1483089Swyllys } else {
1493089Swyllys *len = lc;
1503089Swyllys }
1513089Swyllys
1523089Swyllys return (tag);
1533089Swyllys }
1543089Swyllys
1553089Swyllys
1563089Swyllys /*
1573089Swyllys * Note: Previously, we passed the "ber" parameter directly to
1583089Swyllys * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
1593089Swyllys * We now take advantage of the fact that the only ber structure
1603089Swyllys * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
1613089Swyllys * If that changes, this code must change too.
1623089Swyllys */
1633089Swyllys static ber_tag_t
kmfber_peek_tag(BerElement * ber,ber_len_t * len)1643089Swyllys kmfber_peek_tag(BerElement *ber, ber_len_t *len)
1653089Swyllys {
1663089Swyllys BerElement bercopy;
1673089Swyllys
1683089Swyllys bercopy.ber_end = ber->ber_end;
1693089Swyllys bercopy.ber_ptr = ber->ber_ptr;
1703089Swyllys return (kmfber_skip_tag(&bercopy, len));
1713089Swyllys }
1723089Swyllys
1733089Swyllys static int
ber_getnint(BerElement * ber,ber_int_t * num,ber_slen_t len)1743089Swyllys ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
1753089Swyllys {
1763089Swyllys int i;
1773089Swyllys ber_int_t value;
1783089Swyllys unsigned char buffer[sizeof (ber_int_t)];
1793089Swyllys /*
1803089Swyllys * The tag and length have already been stripped off. We should
1813089Swyllys * be sitting right before len bytes of 2's complement integer,
1823089Swyllys * ready to be read straight into an int. We may have to sign
1833089Swyllys * extend after we read it in.
1843089Swyllys */
1853089Swyllys
18610442Swyllys.ingersoll@sun.com if (len > sizeof (buffer))
1873089Swyllys return (-1);
1883089Swyllys
1893089Swyllys /* read into the low-order bytes of netnum */
1903089Swyllys if (kmfber_read(ber, (char *)buffer, len) != len)
1913089Swyllys return (-1);
1923089Swyllys
1933089Swyllys /* This sets the required sign extension */
1943089Swyllys if (len != 0) {
1953089Swyllys value = 0x80 & buffer[0] ? (-1) : 0;
1963089Swyllys } else {
1973089Swyllys value = 0;
1983089Swyllys }
1993089Swyllys
2003089Swyllys for (i = 0; i < len; i++)
2013089Swyllys value = (value << 8) | buffer[i];
2023089Swyllys
2033089Swyllys *num = value;
2043089Swyllys
2053089Swyllys return (len);
2063089Swyllys }
2073089Swyllys
2083089Swyllys static ber_tag_t
kmfber_get_int(BerElement * ber,ber_int_t * num)2093089Swyllys kmfber_get_int(BerElement *ber, ber_int_t *num)
2103089Swyllys {
2113089Swyllys ber_tag_t tag;
2123089Swyllys ber_len_t len;
2133089Swyllys
2143089Swyllys if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
2153089Swyllys return (KMFBER_DEFAULT);
2163089Swyllys
2173089Swyllys /*
2183089Swyllys * len is being demoted to a long here -- possible conversion error
2193089Swyllys */
2203089Swyllys
2213089Swyllys if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
2223089Swyllys return (KMFBER_DEFAULT);
2233089Swyllys else
2243089Swyllys return (tag);
2253089Swyllys }
2263089Swyllys
2273089Swyllys static ber_tag_t
kmfber_get_stringb(BerElement * ber,char * buf,ber_len_t * len)2283089Swyllys kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
2293089Swyllys {
2303089Swyllys ber_len_t datalen;
2313089Swyllys ber_tag_t tag;
2323089Swyllys #ifdef STR_TRANSLATION
2333089Swyllys char *transbuf;
2343089Swyllys #endif /* STR_TRANSLATION */
2353089Swyllys
2363089Swyllys if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
2373089Swyllys return (KMFBER_DEFAULT);
2383089Swyllys if (datalen > (*len - 1))
2393089Swyllys return (KMFBER_DEFAULT);
2403089Swyllys
2413089Swyllys /*
2423089Swyllys * datalen is being demoted to a long here -- possible conversion error
2433089Swyllys */
2443089Swyllys
2453089Swyllys if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
2463089Swyllys return (KMFBER_DEFAULT);
2473089Swyllys
2483089Swyllys buf[datalen] = '\0';
2493089Swyllys
2503089Swyllys #ifdef STR_TRANSLATION
2513089Swyllys if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
2526051Swyllys != 0 && ber->ber_decode_translate_proc != NULL) {
2533089Swyllys
2543089Swyllys transbuf = buf;
2553089Swyllys ++datalen;
2563089Swyllys if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
2576051Swyllys 0) != 0) {
2583089Swyllys return (KMFBER_DEFAULT);
2593089Swyllys }
2603089Swyllys if (datalen > *len) {
2613089Swyllys free(transbuf);
2623089Swyllys return (KMFBER_DEFAULT);
2633089Swyllys }
2643089Swyllys (void) memmove(buf, transbuf, datalen);
2653089Swyllys free(transbuf);
2663089Swyllys --datalen;
2673089Swyllys }
2683089Swyllys #endif /* STR_TRANSLATION */
2693089Swyllys
2703089Swyllys *len = datalen;
2713089Swyllys return (tag);
2723089Swyllys }
2733089Swyllys
2743089Swyllys static ber_tag_t
kmfber_get_stringa(BerElement * ber,char ** buf)2753089Swyllys kmfber_get_stringa(BerElement *ber, char **buf)
2763089Swyllys {
2773089Swyllys ber_len_t datalen;
2783089Swyllys ber_tag_t tag;
2793089Swyllys
2803089Swyllys if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
2813089Swyllys return (KMFBER_DEFAULT);
2823089Swyllys
2833089Swyllys if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
2843089Swyllys return (KMFBER_DEFAULT);
2853089Swyllys
2863089Swyllys /*
2873089Swyllys * datalen is being demoted to a long here -- possible conversion error
2883089Swyllys */
2893089Swyllys if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
2903089Swyllys return (KMFBER_DEFAULT);
2913089Swyllys (*buf)[datalen] = '\0';
2923089Swyllys
2933089Swyllys return (tag);
2943089Swyllys }
2953089Swyllys
2963089Swyllys ber_tag_t
ber_get_oid(BerElement * ber,struct berval * oid)2973089Swyllys ber_get_oid(BerElement *ber, struct berval *oid)
2983089Swyllys {
2993089Swyllys ber_len_t len;
3003089Swyllys ber_tag_t tag;
3013089Swyllys
3023089Swyllys if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
3033089Swyllys return (KMFBER_DEFAULT);
3043089Swyllys }
3053089Swyllys
3063089Swyllys if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
3073089Swyllys return (KMFBER_DEFAULT);
3083089Swyllys }
3093089Swyllys oid->bv_len = len;
3103089Swyllys
3113089Swyllys if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
3126051Swyllys (ber_slen_t)oid->bv_len)
3133089Swyllys return (KMFBER_DEFAULT);
3143089Swyllys
3153089Swyllys return (tag);
3163089Swyllys }
3173089Swyllys
3183089Swyllys ber_tag_t
ber_get_bigint(BerElement * ber,struct berval ** bv)3193089Swyllys ber_get_bigint(BerElement *ber, struct berval **bv)
3203089Swyllys {
3213089Swyllys ber_len_t len;
3223089Swyllys ber_tag_t tag;
3233089Swyllys
3243089Swyllys if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
3256051Swyllys == NULL) {
3263089Swyllys return (KMFBER_DEFAULT);
3273089Swyllys }
3286051Swyllys (*bv)->bv_len = 0;
3296051Swyllys (*bv)->bv_val = NULL;
3303089Swyllys
3313089Swyllys if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
3323089Swyllys return (KMFBER_DEFAULT);
3333089Swyllys }
3343089Swyllys
3353089Swyllys if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
3366051Swyllys == NULL) {
3373089Swyllys return (KMFBER_DEFAULT);
3383089Swyllys }
3393089Swyllys
3403089Swyllys /*
3413089Swyllys * len is being demoted to a long here -- possible conversion error
3423089Swyllys */
3433089Swyllys if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
3443089Swyllys return (KMFBER_DEFAULT);
3453089Swyllys
3463089Swyllys (*bv)->bv_len = len;
3473089Swyllys
348*11973Swyllys.ingersoll@sun.com /* If DER encoding, strip leading 0's if high-order bit is set */
3493089Swyllys if (ber->ber_options & KMFBER_OPT_USE_DER) {
3503089Swyllys char *p = (*bv)->bv_val;
351*11973Swyllys.ingersoll@sun.com while ((*p == 0x00) && ((*bv)->bv_len > 0) && (p[1] & 0x80)) {
3523089Swyllys p++;
3533089Swyllys (*bv)->bv_len--;
3543089Swyllys }
3553089Swyllys /*
3563089Swyllys * Shift the buffer to the beginning of the allocated space
3573089Swyllys * so it can be properly freed later.
3583089Swyllys */
3593089Swyllys if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
3603089Swyllys (void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
3613089Swyllys }
3623089Swyllys
3633089Swyllys return (tag);
3643089Swyllys }
3653089Swyllys
3663089Swyllys static ber_tag_t
kmfber_get_stringal(BerElement * ber,struct berval ** bv)3673089Swyllys kmfber_get_stringal(BerElement *ber, struct berval **bv)
3683089Swyllys {
3693089Swyllys ber_len_t len;
3703089Swyllys ber_tag_t tag;
3713089Swyllys
3723089Swyllys if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
3736051Swyllys == NULL) {
3743089Swyllys return (KMFBER_DEFAULT);
3753089Swyllys }
3763089Swyllys
3773089Swyllys if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
3783089Swyllys return (KMFBER_DEFAULT);
3793089Swyllys }
3803089Swyllys
3813089Swyllys if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
3826051Swyllys == NULL) {
3833089Swyllys return (KMFBER_DEFAULT);
3843089Swyllys }
3853089Swyllys
3863089Swyllys /*
3873089Swyllys * len is being demoted to a long here -- possible conversion error
3883089Swyllys */
3893089Swyllys if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
3903089Swyllys return (KMFBER_DEFAULT);
3913089Swyllys ((*bv)->bv_val)[len] = '\0';
3923089Swyllys (*bv)->bv_len = len;
3933089Swyllys
3943089Swyllys return (tag);
3953089Swyllys }
3963089Swyllys
3973089Swyllys static ber_tag_t
kmfber_get_bitstringa(BerElement * ber,char ** buf,ber_len_t * blen)3983089Swyllys kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
3993089Swyllys {
4003089Swyllys ber_len_t datalen;
4013089Swyllys ber_tag_t tag;
4023089Swyllys unsigned char unusedbits;
4033089Swyllys
4043089Swyllys if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
4053089Swyllys return (KMFBER_DEFAULT);
4063089Swyllys
4073089Swyllys if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
4083089Swyllys return (KMFBER_DEFAULT);
4093089Swyllys
4103089Swyllys if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
4113089Swyllys return (KMFBER_DEFAULT);
4123089Swyllys
4133089Swyllys /* Subtract 1 for the unused bits */
4143089Swyllys datalen--;
4153089Swyllys
4163089Swyllys /*
4173089Swyllys * datalen is being demoted to a long here -- possible conversion error
4183089Swyllys */
4193089Swyllys if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
4203089Swyllys return (KMFBER_DEFAULT);
4213089Swyllys
4223089Swyllys *blen = datalen * 8 - unusedbits;
4233089Swyllys return (tag);
4243089Swyllys }
4253089Swyllys
4263089Swyllys static ber_tag_t
kmfber_get_null(BerElement * ber)4273089Swyllys kmfber_get_null(BerElement *ber)
4283089Swyllys {
4293089Swyllys ber_len_t len;
4303089Swyllys ber_tag_t tag;
4313089Swyllys
4323089Swyllys if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
4333089Swyllys return (KMFBER_DEFAULT);
4343089Swyllys
4353089Swyllys if (len != 0)
4363089Swyllys return (KMFBER_DEFAULT);
4373089Swyllys
4383089Swyllys return (tag);
4393089Swyllys }
4403089Swyllys
4413089Swyllys static ber_tag_t
kmfber_get_boolean(BerElement * ber,int * boolval)4423089Swyllys kmfber_get_boolean(BerElement *ber, int *boolval)
4433089Swyllys {
4443089Swyllys ber_int_t longbool;
4453089Swyllys int rc;
4463089Swyllys
4473089Swyllys rc = kmfber_get_int(ber, &longbool);
4483089Swyllys *boolval = longbool;
4493089Swyllys
4503089Swyllys return (rc);
4513089Swyllys }
4523089Swyllys
4533089Swyllys ber_tag_t
kmfber_first_element(BerElement * ber,ber_len_t * len,char ** last)4543089Swyllys kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
4553089Swyllys {
4563089Swyllys /* skip the sequence header, use the len to mark where to stop */
4573089Swyllys if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
4583089Swyllys return (KMFBER_ERROR);
4593089Swyllys }
4603089Swyllys
4613089Swyllys *last = ber->ber_ptr + *len;
4623089Swyllys
4633089Swyllys if (*last == ber->ber_ptr) {
4643089Swyllys return (KMFBER_END_OF_SEQORSET);
4653089Swyllys }
4663089Swyllys
4673089Swyllys return (kmfber_peek_tag(ber, len));
4683089Swyllys }
4693089Swyllys
4703089Swyllys ber_tag_t
kmfber_next_element(BerElement * ber,ber_len_t * len,char * last)4713089Swyllys kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
4723089Swyllys {
4733089Swyllys if (ber->ber_ptr == last) {
4743089Swyllys return (KMFBER_END_OF_SEQORSET);
4753089Swyllys }
4763089Swyllys
4773089Swyllys return (kmfber_peek_tag(ber, len));
4783089Swyllys }
4793089Swyllys
4803089Swyllys void
kmfber_bvfree(struct berval * bv)4813089Swyllys kmfber_bvfree(struct berval *bv)
4823089Swyllys {
4833089Swyllys if (bv != NULL) {
4843089Swyllys if (bv->bv_val != NULL) {
4853089Swyllys free(bv->bv_val);
4863089Swyllys }
4873089Swyllys free((char *)bv);
4883089Swyllys }
4893089Swyllys }
4903089Swyllys
4913089Swyllys void
kmfber_bvecfree(struct berval ** bv)4923089Swyllys kmfber_bvecfree(struct berval **bv)
4933089Swyllys {
4943089Swyllys int i;
4953089Swyllys
4963089Swyllys if (bv != NULL) {
4973089Swyllys for (i = 0; bv[i] != NULL; i++) {
4983089Swyllys kmfber_bvfree(bv[i]);
4993089Swyllys }
5003089Swyllys free((char *)bv);
5013089Swyllys }
5023089Swyllys }
5033089Swyllys
5043089Swyllys /* VARARGS */
5053089Swyllys ber_tag_t
kmfber_scanf(BerElement * ber,const char * fmt,...)5063089Swyllys kmfber_scanf(BerElement *ber, const char *fmt, ...)
5073089Swyllys {
5083089Swyllys va_list ap;
5093089Swyllys char *last, *p;
5103089Swyllys char *s, **ss, ***sss;
5113089Swyllys struct berval ***bv, **bvp, *bval;
5123089Swyllys int *i, j;
5133089Swyllys ber_slen_t *l;
5143089Swyllys ber_int_t rc, tag, *b_int;
5153089Swyllys ber_tag_t *t;
5163089Swyllys ber_len_t len;
5173089Swyllys size_t array_size;
5183089Swyllys
5193089Swyllys va_start(ap, fmt);
5203089Swyllys
5213089Swyllys for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
5223089Swyllys switch (*p) {
5236051Swyllys case 'a': /* octet string - allocate storage as needed */
5243089Swyllys ss = va_arg(ap, char **);
5253089Swyllys rc = kmfber_get_stringa(ber, ss);
5263089Swyllys break;
5273089Swyllys
5286051Swyllys case 'b': /* boolean */
5293089Swyllys i = va_arg(ap, int *);
5303089Swyllys rc = kmfber_get_boolean(ber, i);
5313089Swyllys break;
5323089Swyllys
5336051Swyllys case 'D': /* Object ID */
5343089Swyllys bval = va_arg(ap, struct berval *);
5353089Swyllys rc = ber_get_oid(ber, bval);
5363089Swyllys break;
5376051Swyllys case 'e': /* enumerated */
5386051Swyllys case 'i': /* int */
5393089Swyllys b_int = va_arg(ap, ber_int_t *);
5403089Swyllys rc = kmfber_get_int(ber, b_int);
5413089Swyllys break;
5423089Swyllys
5436051Swyllys case 'l': /* length of next item */
5443089Swyllys l = va_arg(ap, ber_slen_t *);
5453089Swyllys rc = kmfber_peek_tag(ber, (ber_len_t *)l);
5463089Swyllys break;
5473089Swyllys
5486051Swyllys case 'n': /* null */
5493089Swyllys rc = kmfber_get_null(ber);
5503089Swyllys break;
5513089Swyllys
5526051Swyllys case 's': /* octet string - in a buffer */
5533089Swyllys s = va_arg(ap, char *);
5543089Swyllys l = va_arg(ap, ber_slen_t *);
5553089Swyllys rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
5563089Swyllys break;
5573089Swyllys
5586051Swyllys case 'o': /* octet string in a supplied berval */
5593089Swyllys bval = va_arg(ap, struct berval *);
5603089Swyllys (void) kmfber_peek_tag(ber, &bval->bv_len);
5613089Swyllys rc = kmfber_get_stringa(ber, &bval->bv_val);
5623089Swyllys break;
5633089Swyllys
5646051Swyllys case 'I': /* variable length Integer */
5653089Swyllys /* Treat INTEGER same as an OCTET string, but ignore the tag */
5663089Swyllys bvp = va_arg(ap, struct berval **);
5673089Swyllys rc = ber_get_bigint(ber, bvp);
5683089Swyllys break;
5696051Swyllys case 'O': /* octet string - allocate & include length */
5703089Swyllys bvp = va_arg(ap, struct berval **);
5713089Swyllys rc = kmfber_get_stringal(ber, bvp);
5723089Swyllys break;
5733089Swyllys
5746051Swyllys case 'B': /* bit string - allocate storage as needed */
5753089Swyllys ss = va_arg(ap, char **);
5763089Swyllys l = va_arg(ap, ber_slen_t *); /* for length, in bits */
5773089Swyllys rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
5783089Swyllys break;
5793089Swyllys
5806051Swyllys case 't': /* tag of next item */
5813089Swyllys t = va_arg(ap, ber_tag_t *);
5823089Swyllys *t = kmfber_peek_tag(ber, &len);
5833089Swyllys rc = (ber_int_t)(*t);
5843089Swyllys break;
5853089Swyllys
5866051Swyllys case 'T': /* skip tag of next item */
5873089Swyllys t = va_arg(ap, ber_tag_t *);
5883089Swyllys *t = kmfber_skip_tag(ber, &len);
5893089Swyllys rc = (ber_int_t)(*t);
5903089Swyllys break;
5913089Swyllys
5926051Swyllys case 'v': /* sequence of strings */
5933089Swyllys sss = va_arg(ap, char ***);
5946051Swyllys if (sss == NULL)
5956051Swyllys break;
5963089Swyllys *sss = NULL;
5973089Swyllys j = 0;
5983089Swyllys array_size = 0;
5993089Swyllys for (tag = kmfber_first_element(ber, &len, &last);
6006051Swyllys (tag != KMFBER_DEFAULT &&
6016051Swyllys tag != KMFBER_END_OF_SEQORSET &&
6026051Swyllys rc != KMFBER_DEFAULT);
6036051Swyllys tag = kmfber_next_element(ber, &len, last)) {
6046051Swyllys if (*sss == NULL) {
6056051Swyllys /* Make room for at least 15 strings */
6066051Swyllys *sss = (char **)malloc(16 * sizeof (char *));
6076051Swyllys array_size = 16;
6086051Swyllys } else {
6096051Swyllys if ((size_t)(j+2) > array_size) {
6106051Swyllys /* We'v overflowed our buffer */
6116051Swyllys *sss = (char **)realloc(*sss,
6126051Swyllys (array_size * 2) * sizeof (char *));
6136051Swyllys array_size = array_size * 2;
6146051Swyllys }
6153089Swyllys }
6166051Swyllys rc = kmfber_get_stringa(ber, &((*sss)[j]));
6176051Swyllys j++;
6183089Swyllys }
6196051Swyllys if (rc != KMFBER_DEFAULT && tag != KMFBER_END_OF_SEQORSET) {
6206051Swyllys rc = KMFBER_DEFAULT;
6213089Swyllys }
6223089Swyllys if (j > 0)
6236051Swyllys (*sss)[j] = NULL;
6243089Swyllys break;
6253089Swyllys
6266051Swyllys case 'V': /* sequence of strings + lengths */
6273089Swyllys bv = va_arg(ap, struct berval ***);
6283089Swyllys *bv = NULL;
6293089Swyllys j = 0;
6303089Swyllys for (tag = kmfber_first_element(ber, &len, &last);
6316051Swyllys (tag != KMFBER_DEFAULT &&
6326051Swyllys tag != KMFBER_END_OF_SEQORSET &&
6336051Swyllys rc != KMFBER_DEFAULT);
6346051Swyllys tag = kmfber_next_element(ber, &len, last)) {
6356051Swyllys if (*bv == NULL) {
6366051Swyllys *bv = (struct berval **)malloc(
6376051Swyllys 2 * sizeof (struct berval *));
6386051Swyllys } else {
6396051Swyllys *bv = (struct berval **)realloc(*bv,
6406051Swyllys (j + 2) * sizeof (struct berval *));
6416051Swyllys }
6426051Swyllys rc = kmfber_get_stringal(ber, &((*bv)[j]));
6436051Swyllys j++;
6443089Swyllys }
6453089Swyllys if (rc != KMFBER_DEFAULT &&
6466051Swyllys tag != KMFBER_END_OF_SEQORSET) {
6476051Swyllys rc = KMFBER_DEFAULT;
6483089Swyllys }
6493089Swyllys if (j > 0)
6506051Swyllys (*bv)[j] = NULL;
6513089Swyllys break;
6523089Swyllys
6536051Swyllys case 'x': /* skip the next element - whatever it is */
6543089Swyllys if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
6556051Swyllys break;
6563089Swyllys ber->ber_ptr += len;
6573089Swyllys break;
6583089Swyllys
6596051Swyllys case '{': /* begin sequence */
6606051Swyllys case '[': /* begin set */
6613089Swyllys if (*(p + 1) != 'v' && *(p + 1) != 'V')
6626051Swyllys rc = kmfber_skip_tag(ber, &len);
6633089Swyllys break;
6643089Swyllys
6656051Swyllys case '}': /* end sequence */
6666051Swyllys case ']': /* end set */
6676051Swyllys break;
6686051Swyllys
6696051Swyllys default:
6703089Swyllys rc = KMFBER_DEFAULT;
6713089Swyllys break;
6726051Swyllys }
6733089Swyllys }
6743089Swyllys
6753089Swyllys
6763089Swyllys va_end(ap);
6773089Swyllys if (rc == KMFBER_DEFAULT) {
6783089Swyllys va_start(ap, fmt);
6793089Swyllys for (p--; fmt < p && *fmt; fmt++) {
6806051Swyllys switch (*fmt) {
6813089Swyllys case 'a': /* octet string - allocate storage as needed */
6826051Swyllys ss = va_arg(ap, char **);
6836051Swyllys if (ss != NULL && *ss != NULL) {
6846051Swyllys free(*ss);
6856051Swyllys *ss = NULL;
6866051Swyllys }
6876051Swyllys break;
6883089Swyllys
6893089Swyllys case 'b': /* boolean */
6906051Swyllys i = va_arg(ap, int *);
6916051Swyllys break;
6923089Swyllys
6933089Swyllys case 'e': /* enumerated */
6943089Swyllys case 'i': /* int */
6956051Swyllys l = va_arg(ap, ber_slen_t *);
6966051Swyllys break;
6973089Swyllys
6983089Swyllys case 'l': /* length of next item */
6996051Swyllys l = va_arg(ap, ber_slen_t *);
7006051Swyllys break;
7013089Swyllys
7023089Swyllys case 'n': /* null */
7036051Swyllys break;
7043089Swyllys
7053089Swyllys case 's': /* octet string - in a buffer */
7066051Swyllys s = va_arg(ap, char *);
7076051Swyllys l = va_arg(ap, ber_slen_t *);
7086051Swyllys break;
7093089Swyllys
7103089Swyllys case 'o': /* octet string in a supplied berval */
7116051Swyllys bval = va_arg(ap, struct berval *);
7126051Swyllys if (bval->bv_val) free(bval->bv_val);
7136051Swyllys (void) memset(bval, 0, sizeof (struct berval));
7146051Swyllys break;
7153089Swyllys
7163089Swyllys case 'O': /* octet string - allocate & include length */
7176051Swyllys bvp = va_arg(ap, struct berval **);
7186051Swyllys kmfber_bvfree(*bvp);
7196051Swyllys bvp = NULL;
7206051Swyllys break;
7213089Swyllys
7223089Swyllys case 'B': /* bit string - allocate storage as needed */
7236051Swyllys ss = va_arg(ap, char **);
7246051Swyllys l = va_arg(ap, ber_slen_t *); /* for length, in bits */
7256051Swyllys if (ss != NULL && *ss != NULL) {
7266051Swyllys free(*ss);
7276051Swyllys *ss = NULL;
7286051Swyllys }
7296051Swyllys break;
7303089Swyllys
7313089Swyllys case 't': /* tag of next item */
7326051Swyllys t = va_arg(ap, ber_tag_t *);
7336051Swyllys break;
7343089Swyllys case 'T': /* skip tag of next item */
7356051Swyllys t = va_arg(ap, ber_tag_t *);
7366051Swyllys break;
7373089Swyllys
7383089Swyllys case 'v': /* sequence of strings */
7396051Swyllys sss = va_arg(ap, char ***);
7406051Swyllys if (sss != NULL && *sss != NULL) {
7416051Swyllys ber_svecfree(*sss);
7426051Swyllys *sss = NULL;
7436051Swyllys }
7446051Swyllys break;
7453089Swyllys
7463089Swyllys case 'V': /* sequence of strings + lengths */
7476051Swyllys bv = va_arg(ap, struct berval ***);
7486051Swyllys kmfber_bvecfree(*bv);
7496051Swyllys *bv = NULL;
7506051Swyllys break;
7513089Swyllys
7523089Swyllys case 'x': /* skip the next element - whatever it is */
7536051Swyllys break;
7543089Swyllys
7553089Swyllys case '{': /* begin sequence */
7563089Swyllys case '[': /* begin set */
7576051Swyllys break;
7583089Swyllys
7593089Swyllys case '}': /* end sequence */
7603089Swyllys case ']': /* end set */
7616051Swyllys break;
7623089Swyllys
7633089Swyllys default:
7646051Swyllys break;
7656051Swyllys }
7663089Swyllys } /* for */
7673089Swyllys va_end(ap);
7683089Swyllys } /* if */
7693089Swyllys
7703089Swyllys return (rc);
7713089Swyllys }
7723089Swyllys
7733089Swyllys struct berval *
kmfber_bvdup(const struct berval * bv)7743089Swyllys kmfber_bvdup(const struct berval *bv)
7753089Swyllys {
7763089Swyllys struct berval *new;
7773089Swyllys
7783089Swyllys if ((new = (struct berval *)malloc(sizeof (struct berval)))
7796051Swyllys == NULL) {
7803089Swyllys return (NULL);
7813089Swyllys }
7823089Swyllys if (bv->bv_val == NULL) {
7833089Swyllys new->bv_val = NULL;
7843089Swyllys new->bv_len = 0;
7853089Swyllys } else {
7863089Swyllys if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
7876051Swyllys == NULL) {
7886051Swyllys return (NULL);
7893089Swyllys }
7903089Swyllys (void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
7913089Swyllys new->bv_val[bv->bv_len] = '\0';
7923089Swyllys new->bv_len = bv->bv_len;
7933089Swyllys }
7943089Swyllys
7953089Swyllys return (new);
7963089Swyllys }
797