1/* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6#pragma ident "%Z%%M% %I% %E% SMI" 7 8/* encode.c - ber output encoding routines */ 9/* 10 * Copyright (c) 1990 Regents of the University of Michigan. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that this notice is preserved and that due credit is given 15 * to the University of Michigan at Ann Arbor. The name of the University 16 * may not be used to endorse or promote products derived from this 17 * software without specific prior written permission. This software 18 * is provided ``as is'' without express or implied warranty. 19 */ 20 21#include <stdio.h> 22#ifdef MACOS 23#include <stdlib.h> 24#include <stdarg.h> 25#include "macos.h" 26#else /* MACOS */ 27#if defined(NeXT) || defined(VMS) 28#include <stdlib.h> 29#else /* next || vms */ 30#include <malloc.h> 31#endif /* next || vms */ 32#if defined( BC31 ) || defined( _WIN32 ) || defined(__sun) 33#include <stdarg.h> 34#else /* BC31 || _WIN32 */ 35#include <varargs.h> 36#endif /* BC31 || _WIN32 */ 37#include <sys/types.h> 38#include <sys/socket.h> 39#include <netinet/in.h> 40#ifdef PCNFS 41#include <tklib.h> 42#endif /* PCNFS */ 43#endif /* MACOS */ 44#ifndef VMS 45#include <memory.h> 46#endif 47#include <string.h> 48#include "lber.h" 49#include "ldap.h" 50#include "ldap-private.h" 51#include "ldap-int.h" 52 53#if defined( DOS ) || defined( _WIN32 ) 54#include "msdos.h" 55#endif /* DOS */ 56 57#ifdef NEEDPROTOS 58static int ber_put_len( BerElement *ber, unsigned int len, int nosos ); 59static int ber_start_seqorset( BerElement *ber, unsigned int tag ); 60static int ber_put_seqorset( BerElement *ber ); 61static int ber_put_int_or_enum( BerElement *ber, int num, unsigned int tag ); 62#endif /* NEEDPROTOS */ 63 64extern int ber_realloc(BerElement *ber, unsigned int len); 65 66static int 67ber_calc_taglen( unsigned int tag ) 68{ 69 int i; 70 int mask; 71 72 /* find the first non-all-zero byte in the tag */ 73 for ( i = sizeof(int) - 1; i > 0; i-- ) { 74 mask = (0xffL << (i * 8)); 75 /* not all zero */ 76 if ( tag & mask ) 77 break; 78 } 79 80 return( i + 1 ); 81} 82 83static int 84ber_put_tag( BerElement *ber, unsigned int tag, int nosos ) 85{ 86 int taglen; 87 unsigned int ntag; 88 89 taglen = ber_calc_taglen( tag ); 90 91 ntag = LBER_HTONL( tag ); 92 93 return( ber_write( ber, ((char *) &ntag) + sizeof(int) - taglen, 94 taglen, nosos ) ); 95} 96 97static int 98ber_calc_lenlen( unsigned int len ) 99{ 100 /* 101 * short len if it's less than 128 - one byte giving the len, 102 * with bit 8 0. 103 */ 104 105 if ( len <= 0x7F ) 106 return( 1 ); 107 108 /* 109 * int len otherwise - one byte with bit 8 set, giving the 110 * length of the length, followed by the length itself. 111 */ 112 113 if ( len <= 0xFF ) 114 return( 2 ); 115 if ( len <= 0xFFFF ) 116 return( 3 ); 117 if ( len <= 0xFFFFFF ) 118 return( 4 ); 119 120 return( 5 ); 121} 122 123static int 124ber_put_len( BerElement *ber, unsigned int len, int nosos ) 125{ 126 int i; 127 char lenlen; 128 int mask; 129 unsigned int netlen; 130 131 /* 132 * short len if it's less than 128 - one byte giving the len, 133 * with bit 8 0. 134 */ 135 136 if ( len <= 127 ) { 137 netlen = LBER_HTONL( len ); 138 return( ber_write( ber, (char *) &netlen + sizeof(int) - 1, 139 1, nosos ) ); 140 } 141 142 /* 143 * int len otherwise - one byte with bit 8 set, giving the 144 * length of the length, followed by the length itself. 145 */ 146 147 /* find the first non-all-zero byte */ 148 for ( i = sizeof(int) - 1; i > 0; i-- ) { 149 mask = (0xff << (i * 8)); 150 /* not all zero */ 151 if ( len & mask ) 152 break; 153 } 154 lenlen = ++i; 155 if ( lenlen > 4 ) 156 return( -1 ); 157 lenlen |= 0x80; 158 159 /* write the length of the length */ 160 if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) 161 return( -1 ); 162 163 /* write the length itself */ 164 netlen = LBER_HTONL( len ); 165 if ( ber_write( ber, (char *) &netlen + (sizeof(int) - i), i, nosos ) 166 != i ) 167 return( -1 ); 168 169 return( i + 1 ); 170} 171 172static int 173ber_put_int_or_enum( BerElement *ber, int num, unsigned int tag ) 174{ 175 int i, sign, taglen; 176 int len, lenlen; 177 int netnum, mask; 178 179 sign = (num < 0); 180 181 /* 182 * high bit is set - look for first non-all-one byte 183 * high bit is clear - look for first non-all-zero byte 184 */ 185 for ( i = sizeof(int) - 1; i > 0; i-- ) { 186 mask = (0xff << (i * 8)); 187 188 if ( sign ) { 189 /* not all ones */ 190 if ( (num & mask) != mask ) 191 break; 192 } else { 193 /* not all zero */ 194 if ( num & mask ) 195 break; 196 } 197 } 198 199 /* 200 * we now have the "leading byte". if the high bit on this 201 * byte matches the sign bit, we need to "back up" a byte. 202 */ 203 mask = (num & (0x80 << (i * 8))); 204 if ( (mask && !sign) || (sign && !mask) ) 205 i++; 206 207 len = i + 1; 208 209 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 210 return( -1 ); 211 212 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) 213 return( -1 ); 214 i++; 215 netnum = LBER_HTONL( num ); 216 if ( ber_write( ber, (char *) &netnum + (sizeof(int) - i), i, 0 ) 217 != i ) 218 return( -1 ); 219 220 /* length of tag + length + contents */ 221 return( taglen + lenlen + i ); 222} 223 224int 225ber_put_enum( BerElement *ber, int num, unsigned int tag ) 226{ 227 if ( tag == LBER_DEFAULT ) 228 tag = LBER_ENUMERATED; 229 230 return( ber_put_int_or_enum( ber, num, tag ) ); 231} 232 233int 234ber_put_int( BerElement *ber, int num, unsigned int tag ) 235{ 236 if ( tag == LBER_DEFAULT ) 237 tag = LBER_INTEGER; 238 239 return( ber_put_int_or_enum( ber, num, tag ) ); 240} 241 242int 243ber_put_ostring( BerElement *ber, char *str, unsigned int len, 244 unsigned int tag ) 245{ 246 int taglen, lenlen, rc; 247#ifdef STR_TRANSLATION 248 int free_str; 249#endif /* STR_TRANSLATION */ 250 251 if ( tag == LBER_DEFAULT ) 252 tag = LBER_OCTETSTRING; 253 254 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 255 return( -1 ); 256 257#ifdef STR_TRANSLATION 258 if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0 && 259 ber->ber_encode_translate_proc != NULL ) { 260 if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 ) 261 != 0 ) { 262 return( -1 ); 263 } 264 free_str = 1; 265 } else { 266 free_str = 0; 267 } 268#endif /* STR_TRANSLATION */ 269 270 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 || 271 ber_write( ber, str, len, 0 ) != len ) { 272 rc = -1; 273 } else { 274 /* return length of tag + length + contents */ 275 rc = taglen + lenlen + len; 276 } 277 278#ifdef STR_TRANSLATION 279 if ( free_str ) { 280 free( str ); 281 } 282#endif /* STR_TRANSLATION */ 283 284 return( rc ); 285} 286 287int 288ber_put_string( BerElement *ber, char *str, unsigned int tag ) 289{ 290 return( ber_put_ostring( ber, str, (unsigned int)strlen( str ), tag )); 291} 292 293int 294ber_put_bitstring( BerElement *ber, char *str, 295 unsigned int blen /* in bits */, unsigned int tag ) 296{ 297 int taglen, lenlen, len; 298 unsigned char unusedbits; 299 300 if ( tag == LBER_DEFAULT ) 301 tag = LBER_BITSTRING; 302 303 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 304 return( -1 ); 305 306 len = ( blen + 7 ) / 8; 307 unusedbits = len * 8 - blen; 308 if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) 309 return( -1 ); 310 311 if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) 312 return( -1 ); 313 314 if ( ber_write( ber, str, len, 0 ) != len ) 315 return( -1 ); 316 317 /* return length of tag + length + unused bit count + contents */ 318 return( taglen + 1 + lenlen + len ); 319} 320 321int 322ber_put_null( BerElement *ber, unsigned int tag ) 323{ 324 int taglen; 325 326 if ( tag == LBER_DEFAULT ) 327 tag = LBER_NULL; 328 329 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 330 return( -1 ); 331 332 if ( ber_put_len( ber, 0, 0 ) != 1 ) 333 return( -1 ); 334 335 return( taglen + 1 ); 336} 337 338int 339ber_put_boolean( BerElement *ber, int boolval, unsigned int tag ) 340{ 341 int taglen; 342 unsigned char trueval = 0xff; 343 unsigned char falseval = 0x00; 344 345 if ( tag == LBER_DEFAULT ) 346 tag = LBER_BOOLEAN; 347 348 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 349 return( -1 ); 350 351 if ( ber_put_len( ber, 1, 0 ) != 1 ) 352 return( -1 ); 353 354 if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 ) 355 != 1 ) 356 return( -1 ); 357 358 return( taglen + 2 ); 359} 360 361#define FOUR_BYTE_LEN 5 362 363static int 364ber_start_seqorset( BerElement *ber, unsigned int tag ) 365{ 366 Seqorset *new; 367 368 if ( (new = (Seqorset *) calloc( sizeof(Seqorset), 1 )) 369 == NULLSEQORSET ) 370 return( -1 ); 371 new->sos_ber = ber; 372 if ( ber->ber_sos == NULLSEQORSET ) 373 new->sos_first = ber->ber_ptr; 374 else 375 new->sos_first = ber->ber_sos->sos_ptr; 376 377 /* Set aside room for a 4 byte length field */ 378 new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN; 379 new->sos_tag = tag; 380 381 new->sos_next = ber->ber_sos; 382 ber->ber_sos = new; 383 if (ber->ber_sos->sos_ptr > ber->ber_end) 384 ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end); 385 386 return( 0 ); 387} 388 389int 390ber_start_seq( BerElement *ber, unsigned int tag ) 391{ 392 if ( tag == LBER_DEFAULT ) 393 tag = LBER_SEQUENCE; 394 395 return( ber_start_seqorset( ber, tag ) ); 396} 397 398int 399ber_start_set( BerElement *ber, unsigned int tag ) 400{ 401 if ( tag == LBER_DEFAULT ) 402 tag = LBER_SET; 403 404 return( ber_start_seqorset( ber, tag ) ); 405} 406 407static int 408ber_put_seqorset( BerElement *ber ) 409{ 410 unsigned int len, netlen; 411 int taglen, lenlen; 412 unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; 413 Seqorset *next; 414 Seqorset **sos = &ber->ber_sos; 415 416 /* 417 * If this is the toplevel sequence or set, we need to actually 418 * write the stuff out. Otherwise, it's already been put in 419 * the appropriate buffer and will be written when the toplevel 420 * one is written. In this case all we need to do is update the 421 * length and tag. 422 */ 423 424 len = (*sos)->sos_clen; 425 netlen = LBER_HTONL( len ); 426 /* CONSTCOND */ 427 if ( sizeof(int) > 4 && len > 0xFFFFFFFF ) 428 return( -1 ); 429 430 if ( ber->ber_options & LBER_USE_DER ) { 431 lenlen = ber_calc_lenlen( len ); 432 } else { 433 lenlen = FOUR_BYTE_LEN; 434 } 435 436 if ( (next = (*sos)->sos_next) == NULLSEQORSET ) { 437 /* write the tag */ 438 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) 439 return( -1 ); 440 441 if ( ber->ber_options & LBER_USE_DER ) { 442 /* Write the length in the minimum # of octets */ 443 if ( ber_put_len( ber, len, 1 ) == -1 ) 444 return( -1 ); 445 446 if (lenlen != FOUR_BYTE_LEN) { 447 /* 448 * We set aside FOUR_BYTE_LEN bytes for 449 * the length field. Move the data if 450 * we don't actually need that much 451 */ 452 (void) SAFEMEMCPY( (*sos)->sos_first + taglen + 453 lenlen, (*sos)->sos_first + taglen + 454 FOUR_BYTE_LEN, len ); 455 } 456 } else { 457 /* Fill FOUR_BYTE_LEN bytes for length field */ 458 /* one byte of length length */ 459 if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 ) 460 return( -1 ); 461 462 /* the length itself */ 463 if ( ber_write( ber, (char *) &netlen + sizeof(int) 464 - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 ) 465 != FOUR_BYTE_LEN - 1 ) 466 return( -1 ); 467 } 468 /* The ber_ptr is at the set/seq start - move it to the end */ 469 (*sos)->sos_ber->ber_ptr += len; 470 } else { 471 unsigned int ntag; 472 473 /* the tag */ 474 taglen = ber_calc_taglen( (*sos)->sos_tag ); 475 ntag = LBER_HTONL( (*sos)->sos_tag ); 476 (void) SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag + 477 sizeof(int) - taglen, taglen ); 478 479 if ( ber->ber_options & LBER_USE_DER ) { 480 ltag = (lenlen == 1) ? len : 0x80 + (lenlen - 1); 481 } 482 483 /* one byte of length length */ 484 (void) SAFEMEMCPY( (*sos)->sos_first + 1, <ag, 1 ); 485 486 if ( ber->ber_options & LBER_USE_DER ) { 487 if (lenlen > 1) { 488 /* Write the length itself */ 489 (void) SAFEMEMCPY( (*sos)->sos_first + 2, 490 (char *)&netlen + sizeof(unsigned int) - 491 (lenlen - 1), 492 lenlen - 1 ); 493 } 494 if (lenlen != FOUR_BYTE_LEN) { 495 /* 496 * We set aside FOUR_BYTE_LEN bytes for 497 * the length field. Move the data if 498 * we don't actually need that much 499 */ 500 (void) SAFEMEMCPY( (*sos)->sos_first + taglen + 501 lenlen, (*sos)->sos_first + taglen + 502 FOUR_BYTE_LEN, len ); 503 } 504 } else { 505 /* the length itself */ 506 (void) SAFEMEMCPY( (*sos)->sos_first + taglen + 1, 507 (char *) &netlen + sizeof(int) - 508 (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 ); 509 } 510 511 next->sos_clen += (taglen + lenlen + len); 512 next->sos_ptr += (taglen + lenlen + len); 513 } 514 515 /* we're done with this seqorset, so free it up */ 516 free( (char *) (*sos) ); 517 *sos = next; 518 519 return( taglen + lenlen + len ); 520} 521 522int 523ber_put_seq( BerElement *ber ) 524{ 525 return( ber_put_seqorset( ber ) ); 526} 527 528int 529ber_put_set( BerElement *ber ) 530{ 531 return( ber_put_seqorset( ber ) ); 532} 533 534/* VARARGS */ 535int 536ber_printf( 537#if defined(MACOS) || defined(_WIN32) || defined(BC31) || defined(__sun) 538 BerElement *ber, char *fmt, ... ) 539#else /* MACOS || _WIN32 || BC31 */ 540 va_alist ) 541va_dcl 542#endif /* MACOS || _WIN32 || BC31 */ 543{ 544 va_list ap; 545#if !defined(MACOS) && !defined(_WIN32) && !defined(BC31) && !defined(__sun) 546 BerElement *ber; 547 char *fmt; 548#endif /* !MACOS && !_WIN32 && !BC31 */ 549 char *s, **ss; 550 struct berval **bv; 551 int rc, i; 552 unsigned int len; 553 554#if defined(MACOS) || defined(_WIN32) || defined(BC31) || defined(__sun) 555 va_start( ap, fmt ); 556#else /* MACOS || _WIN32 || BC31 */ 557 va_start( ap ); 558 ber = va_arg( ap, BerElement * ); 559 fmt = va_arg( ap, char * ); 560#endif /* MACOS || _WIN32 || BC31 */ 561 562 for ( rc = 0; *fmt && rc != -1; fmt++ ) { 563 switch ( *fmt ) { 564 case 'b': /* boolean */ 565 i = va_arg( ap, int ); 566 rc = ber_put_boolean( ber, i, ber->ber_tag ); 567 break; 568 569 case 'i': /* int */ 570 i = va_arg( ap, int ); 571 rc = ber_put_int( ber, i, ber->ber_tag ); 572 break; 573 574 case 'e': /* enumeration */ 575 i = va_arg( ap, int ); 576 rc = ber_put_enum( ber, i, ber->ber_tag ); 577 break; 578 579 case 'n': /* null */ 580 rc = ber_put_null( ber, ber->ber_tag ); 581 break; 582 583 case 'o': /* octet string (non-null terminated) */ 584 s = va_arg( ap, char * ); 585 len = va_arg( ap, int ); 586 rc = ber_put_ostring( ber, s, len, ber->ber_tag ); 587 break; 588 589 case 's': /* string */ 590 s = va_arg( ap, char * ); 591 rc = ber_put_string( ber, s, ber->ber_tag ); 592 break; 593 594 case 'B': /* bit string */ 595 s = va_arg( ap, char * ); 596 len = va_arg( ap, int ); /* in bits */ 597 rc = ber_put_bitstring( ber, s, len, ber->ber_tag ); 598 break; 599 600 case 't': /* tag for the next element */ 601 ber->ber_tag = va_arg( ap, unsigned int ); 602 ber->ber_usertag = 1; 603 break; 604 605 case 'v': /* vector of strings */ 606 if ( (ss = va_arg( ap, char ** )) == NULL ) 607 break; 608 for ( i = 0; ss[i] != NULL; i++ ) { 609 if ( (rc = ber_put_string( ber, ss[i], 610 ber->ber_tag )) == -1 ) 611 break; 612 } 613 break; 614 615 case 'V': /* sequences of strings + lengths */ 616 if ( (bv = va_arg( ap, struct berval ** )) == NULL ) 617 break; 618 for ( i = 0; bv[i] != NULL; i++ ) { 619 if ( (rc = ber_put_ostring( ber, bv[i]->bv_val, 620 bv[i]->bv_len, ber->ber_tag )) == -1 ) 621 break; 622 } 623 break; 624 625 case '{': /* begin sequence */ 626 rc = ber_start_seq( ber, ber->ber_tag ); 627 break; 628 629 case '}': /* end sequence */ 630 rc = ber_put_seqorset( ber ); 631 break; 632 633 case '[': /* begin set */ 634 rc = ber_start_set( ber, ber->ber_tag ); 635 break; 636 637 case ']': /* end set */ 638 rc = ber_put_seqorset( ber ); 639 break; 640 641 default: 642#ifndef NO_USERINTERFACE 643 (void) fprintf( stderr, catgets(slapdcat, 1, 74, "unknown fmt %c\n"), *fmt ); 644#endif /* NO_USERINTERFACE */ 645 rc = -1; 646 break; 647 } 648 649 if ( ber->ber_usertag == 0 ) 650 ber->ber_tag = LBER_DEFAULT; 651 else 652 ber->ber_usertag = 0; 653 } 654 655 va_end( ap ); 656 657 return( rc ); 658} 659