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 /* encode.c - ber output encoding routines */ 37 38 #include "lber-int.h" 39 40 /* the following constants are used in ber_calc_lenlen */ 41 42 #define LENMASK1 0xFF 43 #define LENMASK2 0xFFFF 44 #define LENMASK3 0xFFFFFF 45 #define LENMASK4 0xFFFFFFFF 46 #define _MASK 0x80 47 48 static int 49 ber_calc_taglen( ber_tag_t tag ) 50 { 51 int i; 52 ber_int_t mask; 53 54 /* find the first non-all-zero byte in the tag */ 55 for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) { 56 mask = (LENMASK3 << (i * 8)); 57 /* not all zero */ 58 if ( tag & mask ) 59 break; 60 } 61 62 return( i + 1 ); 63 } 64 65 static int 66 ber_put_tag( BerElement *ber, ber_tag_t tag, int nosos ) 67 { 68 int taglen; 69 ber_tag_t ntag; 70 71 taglen = ber_calc_taglen( tag ); 72 73 ntag = LBER_HTONL( tag ); 74 75 return( ber_write( ber, ((char *) &ntag) + sizeof(ber_int_t) - taglen, 76 taglen, nosos ) ); 77 } 78 79 static int 80 ber_calc_lenlen( ber_len_t len ) 81 { 82 /* 83 * short len if it's less than 128 - one byte giving the len, 84 * with bit 8 0. 85 */ 86 87 if ( len <= 0x7F ) 88 return( 1 ); 89 90 /* 91 * long len otherwise - one byte with bit 8 set, giving the 92 * length of the length, followed by the length itself. 93 */ 94 95 if ( len <= LENMASK1 ) 96 return( 2 ); 97 if ( len <= LENMASK2 ) 98 return( 3 ); 99 if ( len <= LENMASK3 ) 100 return( 4 ); 101 102 return( 5 ); 103 } 104 105 static int 106 ber_put_len( BerElement *ber, ber_len_t len, int nosos ) 107 { 108 int i; 109 char lenlen; 110 ber_int_t mask; 111 ber_len_t netlen; 112 113 /* 114 * short len if it's less than 128 - one byte giving the len, 115 * with bit 8 0. 116 */ 117 118 if ( len <= 127 ) { 119 netlen = LBER_HTONL( len ); 120 return( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) - 1, 121 1, nosos ) ); 122 } 123 124 /* 125 * long len otherwise - one byte with bit 8 set, giving the 126 * length of the length, followed by the length itself. 127 */ 128 129 /* find the first non-all-zero byte */ 130 for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) { 131 mask = (LENMASK1 << (i * 8)); 132 /* not all zero */ 133 if ( len & mask ) 134 break; 135 } 136 lenlen = ++i; 137 if ( lenlen > 4 ) 138 return( -1 ); 139 lenlen |= 0x80; 140 141 /* write the length of the length */ 142 if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) 143 return( -1 ); 144 145 /* write the length itself */ 146 netlen = LBER_HTONL( len ); 147 if ( ber_write( ber, (char *) &netlen + (sizeof(ber_int_t) - i), i, nosos ) 148 != i ) 149 return( -1 ); 150 151 return( i + 1 ); 152 } 153 154 static int 155 ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag ) 156 { 157 int i, sign, taglen; 158 int len, lenlen; 159 ber_int_t netnum, mask; 160 161 sign = (num < 0); 162 163 /* 164 * high bit is set - look for first non-all-one byte 165 * high bit is clear - look for first non-all-zero byte 166 */ 167 for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) { 168 mask = (LENMASK1 << (i * 8)); 169 170 if ( sign ) { 171 /* not all ones */ 172 if ( (num & mask) != mask ) 173 break; 174 } else { 175 /* not all zero */ 176 if ( num & mask ) 177 break; 178 } 179 } 180 181 /* 182 * we now have the "leading byte". if the high bit on this 183 * byte matches the sign bit, we need to "back up" a byte. 184 */ 185 mask = (num & (_MASK << (i * 8))); 186 if ( (mask && !sign) || (sign && !mask) ) 187 i++; 188 189 len = i + 1; 190 191 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 192 return( -1 ); 193 194 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) 195 return( -1 ); 196 i++; 197 netnum = LBER_HTONL( num ); 198 if ( ber_write( ber, (char *) &netnum + (sizeof(ber_int_t) - i), i, 0 ) 199 == i) 200 /* length of tag + length + contents */ 201 return( taglen + lenlen + i ); 202 203 return( -1 ); 204 } 205 206 int 207 LDAP_CALL 208 ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag ) 209 { 210 if ( tag == LBER_DEFAULT ) 211 tag = LBER_ENUMERATED; 212 213 return( ber_put_int_or_enum( ber, num, tag ) ); 214 } 215 216 int 217 LDAP_CALL 218 ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag ) 219 { 220 if ( tag == LBER_DEFAULT ) 221 tag = LBER_INTEGER; 222 223 return( ber_put_int_or_enum( ber, num, tag ) ); 224 } 225 226 int 227 LDAP_CALL 228 ber_put_ostring( BerElement *ber, char *str, ber_len_t len, 229 ber_tag_t tag ) 230 { 231 int taglen, lenlen, rc; 232 #ifdef STR_TRANSLATION 233 int free_str; 234 #endif /* STR_TRANSLATION */ 235 236 if ( tag == LBER_DEFAULT ) 237 tag = LBER_OCTETSTRING; 238 239 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 240 return( -1 ); 241 242 #ifdef STR_TRANSLATION 243 if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0 244 && ber->ber_encode_translate_proc != NULL ) { 245 if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 ) 246 != 0 ) { 247 return( -1 ); 248 } 249 free_str = 1; 250 } else { 251 free_str = 0; 252 } 253 #endif /* STR_TRANSLATION */ 254 255 /* 256 * Note: below is a spot where we limit ber_write 257 * to signed long (instead of unsigned long) 258 */ 259 260 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 || 261 ber_write( ber, str, len, 0 ) != (ber_int_t) len ) { 262 rc = -1; 263 } else { 264 /* return length of tag + length + contents */ 265 rc = taglen + lenlen + len; 266 } 267 268 #ifdef STR_TRANSLATION 269 if ( free_str ) { 270 NSLBERI_FREE( str ); 271 } 272 #endif /* STR_TRANSLATION */ 273 274 return( rc ); 275 } 276 277 int 278 LDAP_CALL 279 ber_put_string( BerElement *ber, char *str, ber_tag_t tag ) 280 { 281 return( ber_put_ostring( ber, str, (ber_len_t) strlen( str ), tag )); 282 } 283 284 int 285 LDAP_CALL 286 ber_put_bitstring( BerElement *ber, char *str, 287 ber_len_t blen /* in bits */, ber_tag_t tag ) 288 { 289 int taglen, lenlen, len; 290 unsigned char unusedbits; 291 292 if ( tag == LBER_DEFAULT ) 293 tag = LBER_BITSTRING; 294 295 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 296 return( -1 ); 297 298 len = ( blen + 7 ) / 8; 299 unusedbits = (unsigned char) (len * 8 - blen); 300 if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) 301 return( -1 ); 302 303 if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) 304 return( -1 ); 305 306 if ( ber_write( ber, str, len, 0 ) != len ) 307 return( -1 ); 308 309 /* return length of tag + length + unused bit count + contents */ 310 return( taglen + 1 + lenlen + len ); 311 } 312 313 int 314 LDAP_CALL 315 ber_put_null( BerElement *ber, ber_tag_t tag ) 316 { 317 int taglen; 318 319 if ( tag == LBER_DEFAULT ) 320 tag = LBER_NULL; 321 322 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 323 return( -1 ); 324 325 if ( ber_put_len( ber, 0, 0 ) != 1 ) 326 return( -1 ); 327 328 return( taglen + 1 ); 329 } 330 331 int 332 LDAP_CALL 333 ber_put_boolean( BerElement *ber, int boolval, ber_tag_t tag ) 334 { 335 int taglen; 336 unsigned char trueval = 0xff; 337 unsigned char falseval = 0x00; 338 339 if ( tag == LBER_DEFAULT ) 340 tag = LBER_BOOLEAN; 341 342 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 343 return( -1 ); 344 345 if ( ber_put_len( ber, 1, 0 ) != 1 ) 346 return( -1 ); 347 348 if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 ) 349 != 1 ) 350 return( -1 ); 351 352 return( taglen + 2 ); 353 } 354 355 #define FOUR_BYTE_LEN 5 356 357 358 /* the idea here is roughly this: we maintain a stack of these Seqorset 359 * structures. This is pushed when we see the beginning of a new set or 360 * sequence. It is popped when we see the end of a set or sequence. 361 * Since we don't want to malloc and free these structures all the time, 362 * we pre-allocate a small set of them within the ber element structure. 363 * thus we need to spot when we've overflowed this stack and fall back to 364 * malloc'ing instead. 365 */ 366 static int 367 ber_start_seqorset( BerElement *ber, ber_tag_t tag ) 368 { 369 Seqorset *new_sos; 370 371 /* can we fit into the local stack ? */ 372 if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) { 373 /* yes */ 374 new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn]; 375 } else { 376 /* no */ 377 if ( (new_sos = (Seqorset *)NSLBERI_MALLOC( sizeof(Seqorset))) 378 == NULLSEQORSET ) { 379 return( -1 ); 380 } 381 } 382 ber->ber_sos_stack_posn++; 383 384 if ( ber->ber_sos == NULLSEQORSET ) 385 new_sos->sos_first = ber->ber_ptr; 386 else 387 new_sos->sos_first = ber->ber_sos->sos_ptr; 388 389 /* Set aside room for a 4 byte length field */ 390 new_sos->sos_ptr = new_sos->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN; 391 new_sos->sos_tag = tag; 392 393 new_sos->sos_next = ber->ber_sos; 394 new_sos->sos_clen = 0; 395 396 ber->ber_sos = new_sos; 397 if (ber->ber_sos->sos_ptr > ber->ber_end) { 398 nslberi_ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end); 399 } 400 return( 0 ); 401 } 402 403 int 404 LDAP_CALL 405 ber_start_seq( BerElement *ber, ber_tag_t tag ) 406 { 407 if ( tag == LBER_DEFAULT ) 408 tag = LBER_SEQUENCE; 409 410 return( ber_start_seqorset( ber, tag ) ); 411 } 412 413 int 414 LDAP_CALL 415 ber_start_set( BerElement *ber, ber_tag_t tag ) 416 { 417 if ( tag == LBER_DEFAULT ) 418 tag = LBER_SET; 419 420 return( ber_start_seqorset( ber, tag ) ); 421 } 422 423 static int 424 ber_put_seqorset( BerElement *ber ) 425 { 426 ber_len_t len, netlen; 427 int taglen, lenlen; 428 unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; 429 Seqorset *next; 430 Seqorset **sos = &ber->ber_sos; 431 432 /* 433 * If this is the toplevel sequence or set, we need to actually 434 * write the stuff out. Otherwise, it's already been put in 435 * the appropriate buffer and will be written when the toplevel 436 * one is written. In this case all we need to do is update the 437 * length and tag. 438 */ 439 440 len = (*sos)->sos_clen; 441 netlen = LBER_HTONL( len ); 442 if ( sizeof(ber_int_t) > 4 && len > LENMASK4 ) 443 return( -1 ); 444 445 if ( ber->ber_options & LBER_OPT_USE_DER ) { 446 lenlen = ber_calc_lenlen( len ); 447 } else { 448 lenlen = FOUR_BYTE_LEN; 449 } 450 451 if ( (next = (*sos)->sos_next) == NULLSEQORSET ) { 452 /* write the tag */ 453 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) 454 return( -1 ); 455 456 if ( ber->ber_options & LBER_OPT_USE_DER ) { 457 /* Write the length in the minimum # of octets */ 458 if ( ber_put_len( ber, len, 1 ) == -1 ) 459 return( -1 ); 460 461 if (lenlen != FOUR_BYTE_LEN) { 462 /* 463 * We set aside FOUR_BYTE_LEN bytes for 464 * the length field. Move the data if 465 * we don't actually need that much 466 */ 467 SAFEMEMCPY( (*sos)->sos_first + taglen + 468 lenlen, (*sos)->sos_first + taglen + 469 FOUR_BYTE_LEN, len ); 470 } 471 } else { 472 /* Fill FOUR_BYTE_LEN bytes for length field */ 473 /* one byte of length length */ 474 if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 ) 475 return( -1 ); 476 477 /* the length itself */ 478 if ( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) 479 - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 ) 480 != FOUR_BYTE_LEN - 1 ) 481 return( -1 ); 482 } 483 /* The ber_ptr is at the set/seq start - move it to the end */ 484 ber->ber_ptr += len; 485 } else { 486 ber_tag_t ntag; 487 488 /* the tag */ 489 taglen = ber_calc_taglen( (*sos)->sos_tag ); 490 ntag = LBER_HTONL( (*sos)->sos_tag ); 491 SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag + 492 sizeof(ber_int_t) - taglen, taglen ); 493 494 if ( ber->ber_options & LBER_OPT_USE_DER ) { 495 ltag = (lenlen == 1) ? (unsigned char)len : 496 (unsigned char) (0x80 + (lenlen - 1)); 497 } 498 499 /* one byte of length length */ 500 SAFEMEMCPY( (*sos)->sos_first + 1, <ag, 1 ); 501 502 if ( ber->ber_options & LBER_OPT_USE_DER ) { 503 if (lenlen > 1) { 504 /* Write the length itself */ 505 SAFEMEMCPY( (*sos)->sos_first + 2, 506 (char *)&netlen + sizeof(ber_uint_t) - 507 (lenlen - 1), 508 lenlen - 1 ); 509 } 510 if (lenlen != FOUR_BYTE_LEN) { 511 /* 512 * We set aside FOUR_BYTE_LEN bytes for 513 * the length field. Move the data if 514 * we don't actually need that much 515 */ 516 SAFEMEMCPY( (*sos)->sos_first + taglen + 517 lenlen, (*sos)->sos_first + taglen + 518 FOUR_BYTE_LEN, len ); 519 } 520 } else { 521 /* the length itself */ 522 SAFEMEMCPY( (*sos)->sos_first + taglen + 1, 523 (char *) &netlen + sizeof(ber_int_t) - 524 (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 ); 525 } 526 527 next->sos_clen += (taglen + lenlen + len); 528 next->sos_ptr += (taglen + lenlen + len); 529 } 530 531 /* we're done with this seqorset, so free it up */ 532 /* was this one from the local stack ? */ 533 if (ber->ber_sos_stack_posn <= SOS_STACK_SIZE) { 534 /* yes */ 535 } else { 536 /* no */ 537 NSLBERI_FREE( (char *) (*sos) ); 538 } 539 ber->ber_sos_stack_posn--; 540 *sos = next; 541 542 return( taglen + lenlen + len ); 543 } 544 545 int 546 LDAP_CALL 547 ber_put_seq( BerElement *ber ) 548 { 549 return( ber_put_seqorset( ber ) ); 550 } 551 552 int 553 LDAP_CALL 554 ber_put_set( BerElement *ber ) 555 { 556 return( ber_put_seqorset( ber ) ); 557 } 558 559 /* VARARGS */ 560 int 561 LDAP_C 562 ber_printf( BerElement *ber, const char *fmt, ... ) 563 { 564 va_list ap; 565 char *s, **ss; 566 struct berval *bval, **bv; 567 int rc, i; 568 ber_len_t len; 569 570 va_start( ap, fmt ); 571 572 #ifdef LDAP_DEBUG 573 if ( lber_debug & 64 ) { 574 char msg[80]; 575 sprintf( msg, "ber_printf fmt (%s)\n", fmt ); 576 ber_err_print( msg ); 577 } 578 #endif 579 580 for ( rc = 0; *fmt && rc != -1; fmt++ ) { 581 switch ( *fmt ) { 582 case 'b': /* boolean */ 583 i = va_arg( ap, int ); 584 rc = ber_put_boolean( ber, i, ber->ber_tag ); 585 break; 586 587 case 'i': /* int */ 588 i = va_arg( ap, int ); 589 rc = ber_put_int( ber, (ber_int_t)i, ber->ber_tag ); 590 break; 591 592 case 'e': /* enumeration */ 593 i = va_arg( ap, int ); 594 rc = ber_put_enum( ber, (ber_int_t)i, ber->ber_tag ); 595 break; 596 597 case 'n': /* null */ 598 rc = ber_put_null( ber, ber->ber_tag ); 599 break; 600 601 case 'o': /* octet string (non-null terminated) */ 602 s = va_arg( ap, char * ); 603 len = va_arg( ap, int ); 604 rc = ber_put_ostring( ber, s, len, ber->ber_tag ); 605 break; 606 607 case 'O': /* berval octet string */ 608 if( ( bval = va_arg( ap, struct berval * ) ) == NULL ) 609 break; 610 if( bval->bv_len == 0 ) { 611 rc = ber_put_ostring( ber, "", 0, ber->ber_tag ); 612 } else { 613 rc = ber_put_ostring( ber, bval->bv_val, bval->bv_len, 614 ber->ber_tag ); 615 } 616 break; 617 618 case 's': /* string */ 619 s = va_arg( ap, char * ); 620 rc = ber_put_string( ber, s, ber->ber_tag ); 621 break; 622 623 case 'B': /* bit string */ 624 s = va_arg( ap, char * ); 625 len = va_arg( ap, int ); /* in bits */ 626 rc = ber_put_bitstring( ber, s, len, ber->ber_tag ); 627 break; 628 629 case 't': /* tag for the next element */ 630 ber->ber_tag = va_arg( ap, ber_tag_t ); 631 ber->ber_usertag = 1; 632 break; 633 634 case 'v': /* vector of strings */ 635 if ( (ss = va_arg( ap, char ** )) == NULL ) 636 break; 637 for ( i = 0; ss[i] != NULL; i++ ) { 638 if ( (rc = ber_put_string( ber, ss[i], 639 ber->ber_tag )) == -1 ) 640 break; 641 } 642 break; 643 644 case 'V': /* sequences of strings + lengths */ 645 if ( (bv = va_arg( ap, struct berval ** )) == NULL ) 646 break; 647 for ( i = 0; bv[i] != NULL; i++ ) { 648 if ( (rc = ber_put_ostring( ber, bv[i]->bv_val, 649 bv[i]->bv_len, ber->ber_tag )) == -1 ) 650 break; 651 } 652 break; 653 654 case '{': /* begin sequence */ 655 rc = ber_start_seq( ber, ber->ber_tag ); 656 break; 657 658 case '}': /* end sequence */ 659 rc = ber_put_seqorset( ber ); 660 break; 661 662 case '[': /* begin set */ 663 rc = ber_start_set( ber, ber->ber_tag ); 664 break; 665 666 case ']': /* end set */ 667 rc = ber_put_seqorset( ber ); 668 break; 669 670 default: { 671 char msg[80]; 672 sprintf( msg, "unknown fmt %c\n", *fmt ); 673 ber_err_print( msg ); 674 rc = -1; 675 break; 676 } 677 } 678 679 if ( ber->ber_usertag == 0 ) 680 ber->ber_tag = LBER_DEFAULT; 681 else 682 ber->ber_usertag = 0; 683 } 684 685 va_end( ap ); 686 687 return( rc ); 688 } 689