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