1 /* encode.c - ber output encoding routines */ 2 /* $OpenLDAP: pkg/ldap/libraries/liblber/encode.c,v 1.64.2.3 2008/02/11 23:26:41 kurt Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 /* Portions Copyright (c) 1990 Regents of the University of Michigan. 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms are permitted 20 * provided that this notice is preserved and that due credit is given 21 * to the University of Michigan at Ann Arbor. The name of the University 22 * may not be used to endorse or promote products derived from this 23 * software without specific prior written permission. This software 24 * is provided ``as is'' without express or implied warranty. 25 */ 26 /* ACKNOWLEDGEMENTS: 27 * This work was originally developed by the University of Michigan 28 * (as part of U-MICH LDAP). 29 */ 30 31 #include "portable.h" 32 33 #include <ctype.h> 34 #include <stdio.h> 35 36 #include <ac/stdlib.h> 37 38 #include <ac/stdarg.h> 39 #include <ac/socket.h> 40 #include <ac/string.h> 41 42 #include "lber-int.h" 43 44 static int ber_put_len LDAP_P(( 45 BerElement *ber, 46 ber_len_t len, 47 int nosos )); 48 49 static int ber_start_seqorset LDAP_P(( 50 BerElement *ber, 51 ber_tag_t tag )); 52 53 static int ber_put_seqorset LDAP_P(( BerElement *ber )); 54 55 static int ber_put_int_or_enum LDAP_P(( 56 BerElement *ber, 57 ber_int_t num, 58 ber_tag_t tag )); 59 60 #define BER_TOP_BYTE(type) (sizeof(type)-1) 61 #define BER_TOP_MASK(type) ((type)0xffU << (BER_TOP_BYTE(type)*8)) 62 63 static int 64 ber_calc_taglen( ber_tag_t tag ) 65 { 66 int i = BER_TOP_BYTE(ber_tag_t); 67 ber_tag_t mask = BER_TOP_MASK(ber_tag_t); 68 69 /* find the first non-all-zero byte in the tag */ 70 for ( ; i > 0; i-- ) { 71 /* not all zero */ 72 if ( tag & mask ) break; 73 mask >>= 8; 74 } 75 76 return i + 1; 77 } 78 79 static int 80 ber_put_tag( 81 BerElement *ber, 82 ber_tag_t tag, 83 int nosos ) 84 { 85 int rc; 86 int taglen; 87 int i; 88 unsigned char nettag[sizeof(ber_tag_t)]; 89 90 assert( ber != NULL ); 91 assert( LBER_VALID( ber ) ); 92 93 taglen = ber_calc_taglen( tag ); 94 95 for( i=taglen-1; i>=0; i-- ) { 96 nettag[i] = (unsigned char)(tag & 0xffU); 97 tag >>= 8; 98 } 99 100 rc = ber_write( ber, (char *) nettag, taglen, nosos ); 101 102 return rc; 103 } 104 105 static ber_len_t 106 ber_calc_lenlen( ber_len_t len ) 107 { 108 /* 109 * short len if it's less than 128 - one byte giving the len, 110 * with bit 8 0. 111 */ 112 113 if ( len <= (ber_len_t) 0x7FU ) return 1; 114 115 /* 116 * long len otherwise - one byte with bit 8 set, giving the 117 * length of the length, followed by the length itself. 118 */ 119 120 if ( len <= (ber_len_t) 0xffU ) return 2; 121 if ( len <= (ber_len_t) 0xffffU ) return 3; 122 if ( len <= (ber_len_t) 0xffffffU ) return 4; 123 124 return 5; 125 } 126 127 static int 128 ber_put_len( BerElement *ber, ber_len_t len, int nosos ) 129 { 130 int rc; 131 int i,j; 132 char lenlen; 133 ber_len_t mask; 134 unsigned char netlen[sizeof(ber_len_t)]; 135 136 assert( ber != NULL ); 137 assert( LBER_VALID( ber ) ); 138 139 /* 140 * short len if it's less than 128 - one byte giving the len, 141 * with bit 8 0. 142 */ 143 144 if ( len <= 127 ) { 145 char length_byte = (char) len; 146 return ber_write( ber, &length_byte, 1, nosos ); 147 } 148 149 /* 150 * long len otherwise - one byte with bit 8 set, giving the 151 * length of the length, followed by the length itself. 152 */ 153 154 /* find the first non-all-zero byte */ 155 i = BER_TOP_BYTE(ber_len_t); 156 mask = BER_TOP_MASK(ber_len_t); 157 for ( ; i > 0; i-- ) { 158 /* not all zero */ 159 if ( len & mask ) break; 160 mask >>= 8; 161 } 162 lenlen = (unsigned char) ++i; 163 if ( lenlen > 4 ) return -1; 164 165 lenlen |= 0x80UL; 166 167 /* write the length of the length */ 168 if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) return -1; 169 170 for( j=i-1; j>=0; j-- ) { 171 netlen[j] = (unsigned char)(len & 0xffU); 172 len >>= 8; 173 } 174 175 /* write the length itself */ 176 rc = ber_write( ber, (char *) netlen, i, nosos ); 177 178 return rc == i ? i+1 : -1; 179 } 180 181 /* out->bv_len should be the buffer size on input */ 182 int 183 ber_encode_oid( BerValue *in, BerValue *out ) 184 { 185 unsigned char *der; 186 unsigned long val1, val; 187 int i, j, len; 188 char *ptr, *end, *inend; 189 190 assert( in != NULL ); 191 assert( out != NULL ); 192 193 if ( !out->bv_val || out->bv_len < in->bv_len/2 ) 194 return -1; 195 196 der = (unsigned char *) out->bv_val; 197 ptr = in->bv_val; 198 inend = ptr + in->bv_len; 199 200 /* OIDs start with <0-1>.<0-39> or 2.<any>, DER-encoded 40*val1+val2 */ 201 if ( !isdigit( (unsigned char) *ptr )) return -1; 202 val1 = strtoul( ptr, &end, 10 ); 203 if ( end == ptr || val1 > 2 ) return -1; 204 if ( *end++ != '.' || !isdigit( (unsigned char) *end )) return -1; 205 val = strtoul( end, &ptr, 10 ); 206 if ( ptr == end ) return -1; 207 if ( val > (val1 < 2 ? 39 : LBER_OID_COMPONENT_MAX - 80) ) return -1; 208 val += val1 * 40; 209 210 for (;;) { 211 if ( ptr > inend ) return -1; 212 213 len = 0; 214 do { 215 der[len++] = (val & 0xff) | 0x80; 216 } while ( (val >>= 7) != 0 ); 217 der[0] &= 0x7f; 218 for ( i = 0, j = len; i < --j; i++ ) { 219 unsigned char tmp = der[i]; 220 der[i] = der[j]; 221 der[j] = tmp; 222 } 223 der += len; 224 if ( ptr == inend ) 225 break; 226 227 if ( *ptr++ != '.' ) return -1; 228 if ( !isdigit( (unsigned char) *ptr )) return -1; 229 val = strtoul( ptr, &end, 10 ); 230 if ( end == ptr || val > LBER_OID_COMPONENT_MAX ) return -1; 231 ptr = end; 232 } 233 234 out->bv_len = (char *)der - out->bv_val; 235 return 0; 236 } 237 238 static int 239 ber_put_int_or_enum( 240 BerElement *ber, 241 ber_int_t num, 242 ber_tag_t tag ) 243 { 244 int rc; 245 int i, j, sign, taglen, lenlen; 246 ber_len_t len; 247 ber_uint_t unum, mask; 248 unsigned char netnum[sizeof(ber_uint_t)]; 249 250 assert( ber != NULL ); 251 assert( LBER_VALID( ber ) ); 252 253 sign = (num < 0); 254 unum = num; /* Bit fiddling should be done with unsigned values */ 255 256 /* 257 * high bit is set - look for first non-all-one byte 258 * high bit is clear - look for first non-all-zero byte 259 */ 260 i = BER_TOP_BYTE(ber_int_t); 261 mask = BER_TOP_MASK(ber_uint_t); 262 for ( ; i > 0; i-- ) { 263 if ( sign ) { 264 /* not all ones */ 265 if ( (unum & mask) != mask ) break; 266 } else { 267 /* not all zero */ 268 if ( unum & mask ) break; 269 } 270 mask >>= 8; 271 } 272 273 /* 274 * we now have the "leading byte". if the high bit on this 275 * byte matches the sign bit, we need to "back up" a byte. 276 */ 277 mask = (unum & ((ber_uint_t)0x80U << (i * 8))); 278 if ( (mask && !sign) || (sign && !mask) ) { 279 i++; 280 } 281 282 len = i + 1; 283 284 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { 285 return -1; 286 } 287 288 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) { 289 return -1; 290 } 291 i++; 292 293 for( j=i-1; j>=0; j-- ) { 294 netnum[j] = (unsigned char)(unum & 0xffU); 295 unum >>= 8; 296 } 297 298 rc = ber_write( ber, (char *) netnum, i, 0 ); 299 300 /* length of tag + length + contents */ 301 return rc == i ? taglen + lenlen + i : -1; 302 } 303 304 int 305 ber_put_enum( 306 BerElement *ber, 307 ber_int_t num, 308 ber_tag_t tag ) 309 { 310 assert( ber != NULL ); 311 assert( LBER_VALID( ber ) ); 312 313 if ( tag == LBER_DEFAULT ) { 314 tag = LBER_ENUMERATED; 315 } 316 317 return ber_put_int_or_enum( ber, num, tag ); 318 } 319 320 int 321 ber_put_int( 322 BerElement *ber, 323 ber_int_t num, 324 ber_tag_t tag ) 325 { 326 assert( ber != NULL ); 327 assert( LBER_VALID( ber ) ); 328 329 if ( tag == LBER_DEFAULT ) { 330 tag = LBER_INTEGER; 331 } 332 333 return ber_put_int_or_enum( ber, num, tag ); 334 } 335 336 int 337 ber_put_ostring( 338 BerElement *ber, 339 LDAP_CONST char *str, 340 ber_len_t len, 341 ber_tag_t tag ) 342 { 343 int taglen, lenlen, rc; 344 345 assert( ber != NULL ); 346 assert( str != NULL ); 347 348 assert( LBER_VALID( ber ) ); 349 350 if ( tag == LBER_DEFAULT ) { 351 tag = LBER_OCTETSTRING; 352 } 353 354 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 355 return -1; 356 357 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 || 358 (ber_len_t) ber_write( ber, str, len, 0 ) != len ) 359 { 360 rc = -1; 361 } else { 362 /* return length of tag + length + contents */ 363 rc = taglen + lenlen + len; 364 } 365 366 return rc; 367 } 368 369 int 370 ber_put_berval( 371 BerElement *ber, 372 struct berval *bv, 373 ber_tag_t tag ) 374 { 375 assert( ber != NULL ); 376 assert( LBER_VALID( ber ) ); 377 378 if( bv == NULL || bv->bv_len == 0 ) { 379 return ber_put_ostring( ber, "", (ber_len_t) 0, tag ); 380 } 381 382 return ber_put_ostring( ber, bv->bv_val, bv->bv_len, tag ); 383 } 384 385 int 386 ber_put_string( 387 BerElement *ber, 388 LDAP_CONST char *str, 389 ber_tag_t tag ) 390 { 391 assert( ber != NULL ); 392 assert( str != NULL ); 393 394 assert( LBER_VALID( ber ) ); 395 396 return ber_put_ostring( ber, str, strlen( str ), tag ); 397 } 398 399 int 400 ber_put_bitstring( 401 BerElement *ber, 402 LDAP_CONST char *str, 403 ber_len_t blen /* in bits */, 404 ber_tag_t tag ) 405 { 406 int taglen, lenlen; 407 ber_len_t len; 408 unsigned char unusedbits; 409 410 assert( ber != NULL ); 411 assert( str != NULL ); 412 413 assert( LBER_VALID( ber ) ); 414 415 if ( tag == LBER_DEFAULT ) { 416 tag = LBER_BITSTRING; 417 } 418 419 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { 420 return -1; 421 } 422 423 len = ( blen + 7 ) / 8; 424 unusedbits = (unsigned char) ((len * 8) - blen); 425 if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) { 426 return -1; 427 } 428 429 if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) { 430 return -1; 431 } 432 433 if ( (ber_len_t) ber_write( ber, str, len, 0 ) != len ) { 434 return -1; 435 } 436 437 /* return length of tag + length + unused bit count + contents */ 438 return taglen + 1 + lenlen + len; 439 } 440 441 int 442 ber_put_null( BerElement *ber, ber_tag_t tag ) 443 { 444 int taglen; 445 446 assert( ber != NULL ); 447 assert( LBER_VALID( ber ) ); 448 449 if ( tag == LBER_DEFAULT ) { 450 tag = LBER_NULL; 451 } 452 453 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { 454 return -1; 455 } 456 457 if ( ber_put_len( ber, 0, 0 ) != 1 ) { 458 return -1; 459 } 460 461 return taglen + 1; 462 } 463 464 int 465 ber_put_boolean( 466 BerElement *ber, 467 ber_int_t boolval, 468 ber_tag_t tag ) 469 { 470 int taglen; 471 unsigned char c; 472 473 assert( ber != NULL ); 474 assert( LBER_VALID( ber ) ); 475 476 if ( tag == LBER_DEFAULT ) 477 tag = LBER_BOOLEAN; 478 479 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { 480 return -1; 481 } 482 483 if ( ber_put_len( ber, 1, 0 ) != 1 ) { 484 return -1; 485 } 486 487 c = boolval ? (unsigned char) ~0U : (unsigned char) 0U; 488 489 if ( ber_write( ber, (char *) &c, 1, 0 ) != 1 ) { 490 return -1; 491 } 492 493 return taglen + 2; 494 } 495 496 #define FOUR_BYTE_LEN 5 497 498 static int 499 ber_start_seqorset( 500 BerElement *ber, 501 ber_tag_t tag ) 502 { 503 Seqorset *new; 504 505 assert( ber != NULL ); 506 assert( LBER_VALID( ber ) ); 507 508 new = (Seqorset *) ber_memcalloc_x( 1, sizeof(Seqorset), ber->ber_memctx ); 509 510 if ( new == NULL ) { 511 return -1; 512 } 513 514 new->sos_ber = ber; 515 if ( ber->ber_sos == NULL ) { 516 new->sos_first = ber->ber_ptr; 517 } else { 518 new->sos_first = ber->ber_sos->sos_ptr; 519 } 520 521 /* Set aside room for a 4 byte length field */ 522 new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN; 523 new->sos_tag = tag; 524 525 new->sos_next = ber->ber_sos; 526 ber->ber_sos = new; 527 528 return 0; 529 } 530 531 int 532 ber_start_seq( BerElement *ber, ber_tag_t tag ) 533 { 534 assert( ber != NULL ); 535 assert( LBER_VALID( ber ) ); 536 537 if ( tag == LBER_DEFAULT ) { 538 tag = LBER_SEQUENCE; 539 } 540 541 return ber_start_seqorset( ber, tag ); 542 } 543 544 int 545 ber_start_set( BerElement *ber, ber_tag_t tag ) 546 { 547 assert( ber != NULL ); 548 assert( LBER_VALID( ber ) ); 549 550 if ( tag == LBER_DEFAULT ) { 551 tag = LBER_SET; 552 } 553 554 return ber_start_seqorset( ber, tag ); 555 } 556 557 static int 558 ber_put_seqorset( BerElement *ber ) 559 { 560 int rc; 561 ber_len_t len; 562 unsigned char netlen[sizeof(ber_len_t)]; 563 int taglen; 564 ber_len_t lenlen; 565 unsigned char ltag = 0x80U + FOUR_BYTE_LEN - 1; 566 Seqorset *next; 567 Seqorset **sos = &ber->ber_sos; 568 569 assert( ber != NULL ); 570 assert( LBER_VALID( ber ) ); 571 572 if( *sos == NULL ) return -1; 573 574 /* 575 * If this is the toplevel sequence or set, we need to actually 576 * write the stuff out. Otherwise, it's already been put in 577 * the appropriate buffer and will be written when the toplevel 578 * one is written. In this case all we need to do is update the 579 * length and tag. 580 */ 581 582 len = (*sos)->sos_clen; 583 584 if ( sizeof(ber_len_t) > 4 && len > 0xffffffffUL ) { 585 return -1; 586 } 587 588 if ( ber->ber_options & LBER_USE_DER ) { 589 lenlen = ber_calc_lenlen( len ); 590 591 } else { 592 lenlen = FOUR_BYTE_LEN; 593 } 594 595 if( lenlen > 1 ) { 596 int i; 597 ber_len_t j = len; 598 for( i=lenlen-2; i >= 0; i-- ) { 599 netlen[i] = j & 0xffU; 600 j >>= 8; 601 } 602 } else { 603 netlen[0] = (unsigned char)(len & 0x7fU); 604 } 605 606 if ( (next = (*sos)->sos_next) == NULL ) { 607 /* write the tag */ 608 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) { 609 return( -1 ); 610 } 611 612 if ( ber->ber_options & LBER_USE_DER ) { 613 /* Write the length in the minimum # of octets */ 614 if ( ber_put_len( ber, len, 1 ) == -1 ) { 615 return -1; 616 } 617 618 if (lenlen != FOUR_BYTE_LEN) { 619 /* 620 * We set aside FOUR_BYTE_LEN bytes for 621 * the length field. Move the data if 622 * we don't actually need that much 623 */ 624 AC_MEMCPY( (*sos)->sos_first + taglen + 625 lenlen, (*sos)->sos_first + taglen + 626 FOUR_BYTE_LEN, len ); 627 } 628 } else { 629 /* Fill FOUR_BYTE_LEN bytes for length field */ 630 /* one byte of length length */ 631 if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 ) { 632 return -1; 633 } 634 635 /* the length itself */ 636 rc = ber_write( ber, (char *) netlen, FOUR_BYTE_LEN-1, 1 ); 637 638 if( rc != FOUR_BYTE_LEN - 1 ) { 639 return -1; 640 } 641 } 642 /* The ber_ptr is at the set/seq start - move it to the end */ 643 (*sos)->sos_ber->ber_ptr += len; 644 645 } else { 646 int i; 647 unsigned char nettag[sizeof(ber_tag_t)]; 648 ber_tag_t tmptag = (*sos)->sos_tag; 649 650 if( ber->ber_sos->sos_ptr > ber->ber_end ) { 651 /* The sos_ptr exceeds the end of the BerElement 652 * this can happen, for example, when the sos_ptr 653 * is near the end and no data was written for the 654 * 'V'. We must realloc the BerElement to ensure 655 * we don't overwrite the buffer when writing 656 * the tag and length fields. 657 */ 658 ber_len_t ext = ber->ber_sos->sos_ptr - ber->ber_end; 659 660 if( ber_realloc( ber, ext ) != 0 ) { 661 return -1; 662 } 663 } 664 665 /* the tag */ 666 taglen = ber_calc_taglen( tmptag ); 667 668 for( i = taglen-1; i >= 0; i-- ) { 669 nettag[i] = (unsigned char)(tmptag & 0xffU); 670 tmptag >>= 8; 671 } 672 673 AC_FMEMCPY( (*sos)->sos_first, nettag, taglen ); 674 675 if ( ber->ber_options & LBER_USE_DER ) { 676 ltag = (lenlen == 1) 677 ? (unsigned char) len 678 : (unsigned char) (0x80U + (lenlen - 1)); 679 } 680 681 /* one byte of length length */ 682 (*sos)->sos_first[1] = ltag; 683 684 if ( ber->ber_options & LBER_USE_DER ) { 685 if (lenlen > 1) { 686 /* Write the length itself */ 687 AC_FMEMCPY( (*sos)->sos_first + 2, netlen, lenlen - 1 ); 688 } 689 if (lenlen != FOUR_BYTE_LEN) { 690 /* 691 * We set aside FOUR_BYTE_LEN bytes for 692 * the length field. Move the data if 693 * we don't actually need that much 694 */ 695 AC_FMEMCPY( (*sos)->sos_first + taglen + 696 lenlen, (*sos)->sos_first + taglen + 697 FOUR_BYTE_LEN, len ); 698 } 699 } else { 700 /* the length itself */ 701 AC_FMEMCPY( (*sos)->sos_first + taglen + 1, 702 netlen, FOUR_BYTE_LEN - 1 ); 703 } 704 705 next->sos_clen += (taglen + lenlen + len); 706 next->sos_ptr += (taglen + lenlen + len); 707 } 708 709 /* we're done with this seqorset, so free it up */ 710 ber_memfree_x( (char *) (*sos), ber->ber_memctx ); 711 *sos = next; 712 713 return taglen + lenlen + len; 714 } 715 716 int 717 ber_put_seq( BerElement *ber ) 718 { 719 assert( ber != NULL ); 720 assert( LBER_VALID( ber ) ); 721 722 return ber_put_seqorset( ber ); 723 } 724 725 int 726 ber_put_set( BerElement *ber ) 727 { 728 assert( ber != NULL ); 729 assert( LBER_VALID( ber ) ); 730 731 return ber_put_seqorset( ber ); 732 } 733 734 /* N tag */ 735 static ber_tag_t lber_int_null = 0; 736 737 /* VARARGS */ 738 int 739 ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... ) 740 { 741 va_list ap; 742 char *s, **ss; 743 struct berval *bv, **bvp; 744 int rc; 745 ber_int_t i; 746 ber_len_t len; 747 748 assert( ber != NULL ); 749 assert( fmt != NULL ); 750 751 assert( LBER_VALID( ber ) ); 752 753 va_start( ap, fmt ); 754 755 for ( rc = 0; *fmt && rc != -1; fmt++ ) { 756 switch ( *fmt ) { 757 case '!': { /* hook */ 758 BEREncodeCallback *f; 759 void *p; 760 761 f = va_arg( ap, BEREncodeCallback * ); 762 p = va_arg( ap, void * ); 763 764 rc = (*f)( ber, p ); 765 } break; 766 767 case 'b': /* boolean */ 768 i = va_arg( ap, ber_int_t ); 769 rc = ber_put_boolean( ber, i, ber->ber_tag ); 770 break; 771 772 case 'i': /* int */ 773 i = va_arg( ap, ber_int_t ); 774 rc = ber_put_int( ber, i, ber->ber_tag ); 775 break; 776 777 case 'e': /* enumeration */ 778 i = va_arg( ap, ber_int_t ); 779 rc = ber_put_enum( ber, i, ber->ber_tag ); 780 break; 781 782 case 'n': /* null */ 783 rc = ber_put_null( ber, ber->ber_tag ); 784 break; 785 786 case 'N': /* Debug NULL */ 787 if( lber_int_null != 0 ) { 788 /* Insert NULL to ensure peer ignores unknown tags */ 789 rc = ber_put_null( ber, lber_int_null ); 790 } else { 791 rc = 0; 792 } 793 break; 794 795 case 'o': /* octet string (non-null terminated) */ 796 s = va_arg( ap, char * ); 797 len = va_arg( ap, ber_len_t ); 798 rc = ber_put_ostring( ber, s, len, ber->ber_tag ); 799 break; 800 801 case 'O': /* berval octet string */ 802 bv = va_arg( ap, struct berval * ); 803 if( bv == NULL ) break; 804 rc = ber_put_berval( ber, bv, ber->ber_tag ); 805 break; 806 807 case 's': /* string */ 808 s = va_arg( ap, char * ); 809 rc = ber_put_string( ber, s, ber->ber_tag ); 810 break; 811 812 case 'B': /* bit string */ 813 case 'X': /* bit string (deprecated) */ 814 s = va_arg( ap, char * ); 815 len = va_arg( ap, int ); /* in bits */ 816 rc = ber_put_bitstring( ber, s, len, ber->ber_tag ); 817 break; 818 819 case 't': /* tag for the next element */ 820 ber->ber_tag = va_arg( ap, ber_tag_t ); 821 ber->ber_usertag = 1; 822 break; 823 824 case 'v': /* vector of strings */ 825 if ( (ss = va_arg( ap, char ** )) == NULL ) 826 break; 827 for ( i = 0; ss[i] != NULL; i++ ) { 828 if ( (rc = ber_put_string( ber, ss[i], 829 ber->ber_tag )) == -1 ) 830 break; 831 } 832 break; 833 834 case 'V': /* sequences of strings + lengths */ 835 if ( (bvp = va_arg( ap, struct berval ** )) == NULL ) 836 break; 837 for ( i = 0; bvp[i] != NULL; i++ ) { 838 if ( (rc = ber_put_berval( ber, bvp[i], 839 ber->ber_tag )) == -1 ) 840 break; 841 } 842 break; 843 844 case 'W': /* BerVarray */ 845 if ( (bv = va_arg( ap, BerVarray )) == NULL ) 846 break; 847 for ( i = 0; bv[i].bv_val != NULL; i++ ) { 848 if ( (rc = ber_put_berval( ber, &bv[i], 849 ber->ber_tag )) == -1 ) 850 break; 851 } 852 break; 853 854 case '{': /* begin sequence */ 855 rc = ber_start_seq( ber, ber->ber_tag ); 856 break; 857 858 case '}': /* end sequence */ 859 rc = ber_put_seqorset( ber ); 860 break; 861 862 case '[': /* begin set */ 863 rc = ber_start_set( ber, ber->ber_tag ); 864 break; 865 866 case ']': /* end set */ 867 rc = ber_put_seqorset( ber ); 868 break; 869 870 default: 871 if( ber->ber_debug ) { 872 ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, 873 "ber_printf: unknown fmt %c\n", *fmt ); 874 } 875 rc = -1; 876 break; 877 } 878 879 if ( ber->ber_usertag == 0 ) { 880 ber->ber_tag = LBER_DEFAULT; 881 } else { 882 ber->ber_usertag = 0; 883 } 884 } 885 886 va_end( ap ); 887 888 return rc; 889 } 890