1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 27 * 28 * The contents of this file are subject to the Netscape Public License 29 * Version 1.0 (the "NPL"); you may not use this file except in 30 * compliance with the NPL. You may obtain a copy of the NPL at 31 * http://www.mozilla.org/NPL/ 32 * 33 * Software distributed under the NPL is distributed on an "AS IS" basis, 34 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 35 * for the specific language governing rights and limitations under the 36 * NPL. 37 * 38 * The Initial Developer of this code under the NPL is Netscape 39 * Communications Corporation. Portions created by Netscape are 40 * Copyright (C) 1998 Netscape Communications Corporation. All Rights 41 * Reserved. 42 */ 43 44 /* 45 * Copyright (c) 1990 Regents of the University of Michigan. 46 * All rights reserved. 47 * 48 * Redistribution and use in source and binary forms are permitted 49 * provided that this notice is preserved and that due credit is given 50 * to the University of Michigan at Ann Arbor. The name of the University 51 * may not be used to endorse or promote products derived from this 52 * software without specific prior written permission. This software 53 * is provided ``as is'' without express or implied warranty. 54 */ 55 56 /* decode.c - ber input decoding routines */ 57 58 #pragma ident "%Z%%M% %I% %E% SMI" 59 60 #include <strings.h> 61 #include <sys/types.h> 62 #include <netinet/in.h> 63 #include <inttypes.h> 64 65 #include <ber_der.h> 66 #include "kmfber_int.h" 67 68 static void 69 ber_svecfree(char **vals) 70 { 71 int i; 72 73 if (vals == NULL) 74 return; 75 for (i = 0; vals[i] != NULL; i++) 76 free(vals[i]); 77 free((char *)vals); 78 } 79 80 /* 81 * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber. 82 * If that changes, the kmfber_peek_tag() and/or 83 * kmfkmfber_skip_tag() implementations will need to be changed. 84 */ 85 /* return the tag - KMFBER_DEFAULT returned means trouble */ 86 static ber_tag_t 87 kmfber_get_tag(BerElement *ber) 88 { 89 unsigned char xbyte; 90 ber_tag_t tag; 91 char *tagp; 92 int i; 93 94 if (kmfber_read(ber, (char *)&xbyte, 1) != 1) 95 return (KMFBER_DEFAULT); 96 97 if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK) 98 return ((ber_uint_t)xbyte); 99 100 tagp = (char *)&tag; 101 tagp[0] = xbyte; 102 for (i = 1; i < sizeof (ber_int_t); i++) { 103 if (kmfber_read(ber, (char *)&xbyte, 1) != 1) 104 return (KMFBER_DEFAULT); 105 106 tagp[i] = xbyte; 107 108 if (! (xbyte & KMFBER_MORE_TAG_MASK)) 109 break; 110 } 111 112 /* tag too big! */ 113 if (i == sizeof (ber_int_t)) 114 return (KMFBER_DEFAULT); 115 116 /* want leading, not trailing 0's */ 117 return (tag >> (sizeof (ber_int_t)- i - 1)); 118 } 119 120 /* 121 * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber. 122 * If that changes, the implementation of kmfber_peek_tag() will need to 123 * be changed. 124 */ 125 ber_tag_t 126 kmfber_skip_tag(BerElement *ber, ber_len_t *len) 127 { 128 ber_tag_t tag; 129 unsigned char lc; 130 int noctets, diff; 131 uint32_t netlen; 132 133 /* 134 * Any ber element looks like this: tag length contents. 135 * Assuming everything's ok, we return the tag byte (we 136 * can assume a single byte), and return the length in len. 137 * 138 * Assumptions: 139 * 1) definite lengths 140 * 2) primitive encodings used whenever possible 141 */ 142 143 /* 144 * First, we read the tag. 145 */ 146 147 if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT) 148 return (KMFBER_DEFAULT); 149 150 /* 151 * Next, read the length. The first byte contains the length of 152 * the length. If bit 8 is set, the length is the long form, 153 * otherwise it's the short form. We don't allow a length that's 154 * greater than what we can hold in an unsigned long. 155 */ 156 157 *len = 0; 158 netlen = 0; 159 if (kmfber_read(ber, (char *)&lc, 1) != 1) 160 return (KMFBER_DEFAULT); 161 if (lc & 0x80) { 162 noctets = (lc & 0x7f); 163 if (noctets > sizeof (ber_uint_t)) 164 return (KMFBER_DEFAULT); 165 diff = sizeof (ber_int_t) - noctets; 166 if (kmfber_read(ber, (char *)&netlen + diff, noctets) 167 != noctets) 168 return (KMFBER_DEFAULT); 169 *len = ntohl(netlen); 170 } else { 171 *len = lc; 172 } 173 174 return (tag); 175 } 176 177 178 /* 179 * Note: Previously, we passed the "ber" parameter directly to 180 * kmfber_skip_tag(), saving and restoring the ber_ptr element only. 181 * We now take advantage of the fact that the only ber structure 182 * elements touched by kmfber_skip_tag() are ber_end and ber_ptr. 183 * If that changes, this code must change too. 184 */ 185 static ber_tag_t 186 kmfber_peek_tag(BerElement *ber, ber_len_t *len) 187 { 188 BerElement bercopy; 189 190 bercopy.ber_end = ber->ber_end; 191 bercopy.ber_ptr = ber->ber_ptr; 192 return (kmfber_skip_tag(&bercopy, len)); 193 } 194 195 static int 196 ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len) 197 { 198 int i; 199 ber_int_t value; 200 unsigned char buffer[sizeof (ber_int_t)]; 201 /* 202 * The tag and length have already been stripped off. We should 203 * be sitting right before len bytes of 2's complement integer, 204 * ready to be read straight into an int. We may have to sign 205 * extend after we read it in. 206 */ 207 208 if (len > sizeof (ber_slen_t)) 209 return (-1); 210 211 /* read into the low-order bytes of netnum */ 212 if (kmfber_read(ber, (char *)buffer, len) != len) 213 return (-1); 214 215 /* This sets the required sign extension */ 216 if (len != 0) { 217 value = 0x80 & buffer[0] ? (-1) : 0; 218 } else { 219 value = 0; 220 } 221 222 for (i = 0; i < len; i++) 223 value = (value << 8) | buffer[i]; 224 225 *num = value; 226 227 return (len); 228 } 229 230 static ber_tag_t 231 kmfber_get_int(BerElement *ber, ber_int_t *num) 232 { 233 ber_tag_t tag; 234 ber_len_t len; 235 236 if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) 237 return (KMFBER_DEFAULT); 238 239 /* 240 * len is being demoted to a long here -- possible conversion error 241 */ 242 243 if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len) 244 return (KMFBER_DEFAULT); 245 else 246 return (tag); 247 } 248 249 static ber_tag_t 250 kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len) 251 { 252 ber_len_t datalen; 253 ber_tag_t tag; 254 #ifdef STR_TRANSLATION 255 char *transbuf; 256 #endif /* STR_TRANSLATION */ 257 258 if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT) 259 return (KMFBER_DEFAULT); 260 if (datalen > (*len - 1)) 261 return (KMFBER_DEFAULT); 262 263 /* 264 * datalen is being demoted to a long here -- possible conversion error 265 */ 266 267 if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen) 268 return (KMFBER_DEFAULT); 269 270 buf[datalen] = '\0'; 271 272 #ifdef STR_TRANSLATION 273 if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) 274 != 0 && ber->ber_decode_translate_proc != NULL) { 275 276 transbuf = buf; 277 ++datalen; 278 if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen, 279 0) != 0) { 280 return (KMFBER_DEFAULT); 281 } 282 if (datalen > *len) { 283 free(transbuf); 284 return (KMFBER_DEFAULT); 285 } 286 (void) memmove(buf, transbuf, datalen); 287 free(transbuf); 288 --datalen; 289 } 290 #endif /* STR_TRANSLATION */ 291 292 *len = datalen; 293 return (tag); 294 } 295 296 static ber_tag_t 297 kmfber_get_stringa(BerElement *ber, char **buf) 298 { 299 ber_len_t datalen; 300 ber_tag_t tag; 301 302 if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT) 303 return (KMFBER_DEFAULT); 304 305 if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL) 306 return (KMFBER_DEFAULT); 307 308 /* 309 * datalen is being demoted to a long here -- possible conversion error 310 */ 311 if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen) 312 return (KMFBER_DEFAULT); 313 (*buf)[datalen] = '\0'; 314 315 return (tag); 316 } 317 318 ber_tag_t 319 ber_get_oid(BerElement *ber, struct berval *oid) 320 { 321 ber_len_t len; 322 ber_tag_t tag; 323 324 if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) { 325 return (KMFBER_DEFAULT); 326 } 327 328 if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) { 329 return (KMFBER_DEFAULT); 330 } 331 oid->bv_len = len; 332 333 if (kmfber_read(ber, oid->bv_val, oid->bv_len) != 334 (ber_slen_t)oid->bv_len) 335 return (KMFBER_DEFAULT); 336 337 return (tag); 338 } 339 340 ber_tag_t 341 ber_get_bigint(BerElement *ber, struct berval **bv) 342 { 343 ber_len_t len; 344 ber_tag_t tag; 345 346 if ((*bv = (struct berval *)malloc(sizeof (struct berval))) 347 == NULL) { 348 return (KMFBER_DEFAULT); 349 } 350 351 if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) { 352 return (KMFBER_DEFAULT); 353 } 354 355 if (((*bv)->bv_val = (char *)malloc((size_t)len + 1)) 356 == NULL) { 357 return (KMFBER_DEFAULT); 358 } 359 360 /* 361 * len is being demoted to a long here -- possible conversion error 362 */ 363 if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len) 364 return (KMFBER_DEFAULT); 365 366 (*bv)->bv_len = len; 367 368 /* If DER encoding, strip leading 0's */ 369 if (ber->ber_options & KMFBER_OPT_USE_DER) { 370 char *p = (*bv)->bv_val; 371 while ((*p == 0x00) && ((*bv)->bv_len > 0)) { 372 p++; 373 (*bv)->bv_len--; 374 } 375 /* 376 * Shift the buffer to the beginning of the allocated space 377 * so it can be properly freed later. 378 */ 379 if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0)) 380 (void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len); 381 } 382 383 return (tag); 384 } 385 386 static ber_tag_t 387 kmfber_get_stringal(BerElement *ber, struct berval **bv) 388 { 389 ber_len_t len; 390 ber_tag_t tag; 391 392 if ((*bv = (struct berval *)malloc(sizeof (struct berval))) 393 == NULL) { 394 return (KMFBER_DEFAULT); 395 } 396 397 if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) { 398 return (KMFBER_DEFAULT); 399 } 400 401 if (((*bv)->bv_val = (char *)malloc((size_t)len + 1)) 402 == NULL) { 403 return (KMFBER_DEFAULT); 404 } 405 406 /* 407 * len is being demoted to a long here -- possible conversion error 408 */ 409 if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len) 410 return (KMFBER_DEFAULT); 411 ((*bv)->bv_val)[len] = '\0'; 412 (*bv)->bv_len = len; 413 414 return (tag); 415 } 416 417 static ber_tag_t 418 kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen) 419 { 420 ber_len_t datalen; 421 ber_tag_t tag; 422 unsigned char unusedbits; 423 424 if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT) 425 return (KMFBER_DEFAULT); 426 427 if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL) 428 return (KMFBER_DEFAULT); 429 430 if (kmfber_read(ber, (char *)&unusedbits, 1) != 1) 431 return (KMFBER_DEFAULT); 432 433 /* Subtract 1 for the unused bits */ 434 datalen--; 435 436 /* 437 * datalen is being demoted to a long here -- possible conversion error 438 */ 439 if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen) 440 return (KMFBER_DEFAULT); 441 442 *blen = datalen * 8 - unusedbits; 443 return (tag); 444 } 445 446 static ber_tag_t 447 kmfber_get_null(BerElement *ber) 448 { 449 ber_len_t len; 450 ber_tag_t tag; 451 452 if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) 453 return (KMFBER_DEFAULT); 454 455 if (len != 0) 456 return (KMFBER_DEFAULT); 457 458 return (tag); 459 } 460 461 static ber_tag_t 462 kmfber_get_boolean(BerElement *ber, int *boolval) 463 { 464 ber_int_t longbool; 465 int rc; 466 467 rc = kmfber_get_int(ber, &longbool); 468 *boolval = longbool; 469 470 return (rc); 471 } 472 473 ber_tag_t 474 kmfber_first_element(BerElement *ber, ber_len_t *len, char **last) 475 { 476 /* skip the sequence header, use the len to mark where to stop */ 477 if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) { 478 return (KMFBER_ERROR); 479 } 480 481 *last = ber->ber_ptr + *len; 482 483 if (*last == ber->ber_ptr) { 484 return (KMFBER_END_OF_SEQORSET); 485 } 486 487 return (kmfber_peek_tag(ber, len)); 488 } 489 490 ber_tag_t 491 kmfber_next_element(BerElement *ber, ber_len_t *len, char *last) 492 { 493 if (ber->ber_ptr == last) { 494 return (KMFBER_END_OF_SEQORSET); 495 } 496 497 return (kmfber_peek_tag(ber, len)); 498 } 499 500 void 501 kmfber_bvfree(struct berval *bv) 502 { 503 if (bv != NULL) { 504 if (bv->bv_val != NULL) { 505 free(bv->bv_val); 506 } 507 free((char *)bv); 508 } 509 } 510 511 void 512 kmfber_bvecfree(struct berval **bv) 513 { 514 int i; 515 516 if (bv != NULL) { 517 for (i = 0; bv[i] != NULL; i++) { 518 kmfber_bvfree(bv[i]); 519 } 520 free((char *)bv); 521 } 522 } 523 524 /* VARARGS */ 525 ber_tag_t 526 kmfber_scanf(BerElement *ber, const char *fmt, ...) 527 { 528 va_list ap; 529 char *last, *p; 530 char *s, **ss, ***sss; 531 struct berval ***bv, **bvp, *bval; 532 int *i, j; 533 ber_slen_t *l; 534 ber_int_t rc, tag, *b_int; 535 ber_tag_t *t; 536 ber_len_t len; 537 size_t array_size; 538 539 va_start(ap, fmt); 540 541 for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) { 542 switch (*p) { 543 case 'a': /* octet string - allocate storage as needed */ 544 ss = va_arg(ap, char **); 545 rc = kmfber_get_stringa(ber, ss); 546 break; 547 548 case 'b': /* boolean */ 549 i = va_arg(ap, int *); 550 rc = kmfber_get_boolean(ber, i); 551 break; 552 553 case 'D': /* Object ID */ 554 bval = va_arg(ap, struct berval *); 555 rc = ber_get_oid(ber, bval); 556 break; 557 case 'e': /* enumerated */ 558 case 'i': /* int */ 559 b_int = va_arg(ap, ber_int_t *); 560 rc = kmfber_get_int(ber, b_int); 561 break; 562 563 case 'l': /* length of next item */ 564 l = va_arg(ap, ber_slen_t *); 565 rc = kmfber_peek_tag(ber, (ber_len_t *)l); 566 break; 567 568 case 'n': /* null */ 569 rc = kmfber_get_null(ber); 570 break; 571 572 case 's': /* octet string - in a buffer */ 573 s = va_arg(ap, char *); 574 l = va_arg(ap, ber_slen_t *); 575 rc = kmfber_get_stringb(ber, s, (ber_len_t *)l); 576 break; 577 578 case 'o': /* octet string in a supplied berval */ 579 bval = va_arg(ap, struct berval *); 580 (void) kmfber_peek_tag(ber, &bval->bv_len); 581 rc = kmfber_get_stringa(ber, &bval->bv_val); 582 break; 583 584 case 'I': /* variable length Integer */ 585 /* Treat INTEGER same as an OCTET string, but ignore the tag */ 586 bvp = va_arg(ap, struct berval **); 587 rc = ber_get_bigint(ber, bvp); 588 break; 589 case 'O': /* octet string - allocate & include length */ 590 bvp = va_arg(ap, struct berval **); 591 rc = kmfber_get_stringal(ber, bvp); 592 break; 593 594 case 'B': /* bit string - allocate storage as needed */ 595 ss = va_arg(ap, char **); 596 l = va_arg(ap, ber_slen_t *); /* for length, in bits */ 597 rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l); 598 break; 599 600 case 't': /* tag of next item */ 601 t = va_arg(ap, ber_tag_t *); 602 *t = kmfber_peek_tag(ber, &len); 603 rc = (ber_int_t)(*t); 604 break; 605 606 case 'T': /* skip tag of next item */ 607 t = va_arg(ap, ber_tag_t *); 608 *t = kmfber_skip_tag(ber, &len); 609 rc = (ber_int_t)(*t); 610 break; 611 612 case 'v': /* sequence of strings */ 613 sss = va_arg(ap, char ***); 614 *sss = NULL; 615 j = 0; 616 array_size = 0; 617 for (tag = kmfber_first_element(ber, &len, &last); 618 (tag != KMFBER_DEFAULT && 619 tag != KMFBER_END_OF_SEQORSET && 620 rc != KMFBER_DEFAULT); 621 tag = kmfber_next_element(ber, &len, last)) { 622 if (*sss == NULL) { 623 /* Make room for at least 15 strings */ 624 *sss = (char **)malloc(16 * sizeof (char *)); 625 array_size = 16; 626 } else { 627 if ((size_t)(j+2) > array_size) { 628 /* We'v overflowed our buffer */ 629 *sss = (char **)realloc(*sss, 630 (array_size * 2) * sizeof (char *)); 631 array_size = array_size * 2; 632 } 633 } 634 rc = kmfber_get_stringa(ber, &((*sss)[j])); 635 j++; 636 } 637 if (rc != KMFBER_DEFAULT && 638 tag != KMFBER_END_OF_SEQORSET) { 639 rc = KMFBER_DEFAULT; 640 } 641 if (j > 0) 642 (*sss)[j] = NULL; 643 break; 644 645 case 'V': /* sequence of strings + lengths */ 646 bv = va_arg(ap, struct berval ***); 647 *bv = NULL; 648 j = 0; 649 for (tag = kmfber_first_element(ber, &len, &last); 650 (tag != KMFBER_DEFAULT && 651 tag != KMFBER_END_OF_SEQORSET && 652 rc != KMFBER_DEFAULT); 653 tag = kmfber_next_element(ber, &len, last)) { 654 if (*bv == NULL) { 655 *bv = (struct berval **)malloc( 656 2 * sizeof (struct berval *)); 657 } else { 658 *bv = (struct berval **)realloc(*bv, 659 (j + 2) * sizeof (struct berval *)); 660 } 661 rc = kmfber_get_stringal(ber, &((*bv)[j])); 662 j++; 663 } 664 if (rc != KMFBER_DEFAULT && 665 tag != KMFBER_END_OF_SEQORSET) { 666 rc = KMFBER_DEFAULT; 667 } 668 if (j > 0) 669 (*bv)[j] = NULL; 670 break; 671 672 case 'x': /* skip the next element - whatever it is */ 673 if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) 674 break; 675 ber->ber_ptr += len; 676 break; 677 678 case '{': /* begin sequence */ 679 case '[': /* begin set */ 680 if (*(p + 1) != 'v' && *(p + 1) != 'V') 681 rc = kmfber_skip_tag(ber, &len); 682 break; 683 684 case '}': /* end sequence */ 685 case ']': /* end set */ 686 break; 687 688 default: 689 #ifdef KMFBER_DEBUG 690 { 691 char msg[80]; 692 sprintf(msg, "unknown fmt %c\n", *p); 693 ber_err_print(msg); 694 } 695 #endif 696 rc = KMFBER_DEFAULT; 697 break; 698 } 699 } 700 701 702 va_end(ap); 703 if (rc == KMFBER_DEFAULT) { 704 va_start(ap, fmt); 705 for (p--; fmt < p && *fmt; fmt++) { 706 switch (*fmt) { 707 case 'a': /* octet string - allocate storage as needed */ 708 ss = va_arg(ap, char **); 709 free(*ss); 710 *ss = NULL; 711 break; 712 713 case 'b': /* boolean */ 714 i = va_arg(ap, int *); 715 break; 716 717 case 'e': /* enumerated */ 718 case 'i': /* int */ 719 l = va_arg(ap, ber_slen_t *); 720 break; 721 722 case 'l': /* length of next item */ 723 l = va_arg(ap, ber_slen_t *); 724 break; 725 726 case 'n': /* null */ 727 break; 728 729 case 's': /* octet string - in a buffer */ 730 s = va_arg(ap, char *); 731 l = va_arg(ap, ber_slen_t *); 732 break; 733 734 case 'o': /* octet string in a supplied berval */ 735 bval = va_arg(ap, struct berval *); 736 if (bval->bv_val) free(bval->bv_val); 737 (void) memset(bval, 0, sizeof (struct berval)); 738 break; 739 740 case 'O': /* octet string - allocate & include length */ 741 bvp = va_arg(ap, struct berval **); 742 kmfber_bvfree(*bvp); 743 bvp = NULL; 744 break; 745 746 case 'B': /* bit string - allocate storage as needed */ 747 ss = va_arg(ap, char **); 748 l = va_arg(ap, ber_slen_t *); /* for length, in bits */ 749 if (*ss) free(*ss); 750 *ss = NULL; 751 break; 752 753 case 't': /* tag of next item */ 754 t = va_arg(ap, ber_tag_t *); 755 break; 756 case 'T': /* skip tag of next item */ 757 t = va_arg(ap, ber_tag_t *); 758 break; 759 760 case 'v': /* sequence of strings */ 761 sss = va_arg(ap, char ***); 762 ber_svecfree(*sss); 763 *sss = NULL; 764 break; 765 766 case 'V': /* sequence of strings + lengths */ 767 bv = va_arg(ap, struct berval ***); 768 kmfber_bvecfree(*bv); 769 *bv = NULL; 770 break; 771 772 case 'x': /* skip the next element - whatever it is */ 773 break; 774 775 case '{': /* begin sequence */ 776 case '[': /* begin set */ 777 break; 778 779 case '}': /* end sequence */ 780 case ']': /* end set */ 781 break; 782 783 default: 784 break; 785 } 786 } /* for */ 787 va_end(ap); 788 } /* if */ 789 790 791 return (rc); 792 } 793 794 struct berval * 795 kmfber_bvdup(const struct berval *bv) 796 { 797 struct berval *new; 798 799 if ((new = (struct berval *)malloc(sizeof (struct berval))) 800 == NULL) { 801 return (NULL); 802 } 803 if (bv->bv_val == NULL) { 804 new->bv_val = NULL; 805 new->bv_len = 0; 806 } else { 807 if ((new->bv_val = (char *)malloc(bv->bv_len + 1)) 808 == NULL) { 809 return (NULL); 810 } 811 (void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len); 812 new->bv_val[bv->bv_len] = '\0'; 813 new->bv_len = bv->bv_len; 814 } 815 816 return (new); 817 } 818