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