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