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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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