1/* decode.c - ber input decoding routines */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 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 <stdio.h> 34 35#include <ac/stdlib.h> 36#include <ac/stdarg.h> 37#include <ac/string.h> 38#include <ac/socket.h> 39 40#include "lber-int.h" 41 42 43/* out->bv_len should be the buffer size on input */ 44int 45ber_decode_oid( BerValue *in, BerValue *out ) 46{ 47 const unsigned char *der; 48 unsigned long val; 49 unsigned val1; 50 ber_len_t i; 51 char *ptr; 52 53 assert( in != NULL ); 54 assert( out != NULL ); 55 56 /* need 4 chars/inbyte + \0 for input={7f 7f 7f...} */ 57 if ( !out->bv_val || (out->bv_len+3)/4 <= in->bv_len ) 58 return -1; 59 60 ptr = NULL; 61 der = (unsigned char *) in->bv_val; 62 val = 0; 63 for ( i=0; i < in->bv_len; i++ ) { 64 val |= der[i] & 0x7f; 65 if ( !( der[i] & 0x80 )) { 66 if ( ptr == NULL ) { 67 /* Initial "x.y": val=x*40+y, x<=2, y<40 if x<2 */ 68 ptr = out->bv_val; 69 val1 = (val < 80 ? val/40 : 2); 70 val -= val1*40; 71 ptr += sprintf( ptr, "%u", val1 ); 72 } 73 ptr += sprintf( ptr, ".%lu", val ); 74 val = 0; 75 } else if ( val - 1UL < LBER_OID_COMPONENT_MAX >> 7 ) { 76 val <<= 7; 77 } else { 78 /* val would overflow, or is 0 from invalid initial 0x80 octet */ 79 return -1; 80 } 81 } 82 if ( ptr == NULL || val != 0 ) 83 return -1; 84 85 out->bv_len = ptr - out->bv_val; 86 return 0; 87} 88 89/* Return tag, with *bv = rest of element (starting at length octets) */ 90static ber_tag_t 91ber_tag_and_rest( const BerElement *ber, struct berval *bv ) 92{ 93 ber_tag_t tag; 94 ptrdiff_t rest; 95 unsigned char *ptr; 96 97 assert( ber != NULL ); 98 assert( LBER_VALID( ber ) ); 99 100 ptr = (unsigned char *) ber->ber_ptr; 101 rest = (unsigned char *) ber->ber_end - ptr; 102 if ( rest <= 0 ) { 103 goto fail; 104 } 105 106 tag = ber->ber_tag; 107 if ( (char *) ptr == ber->ber_buf ) { 108 tag = *ptr; 109 } 110 ptr++; 111 rest--; 112 if ( (tag & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) { 113 goto done; 114 } 115 116 do { 117 if ( rest <= 0 ) { 118 break; 119 } 120 tag <<= 8; 121 tag |= *ptr++ & 0xffU; 122 rest--; 123 124 if ( ! (tag & LBER_MORE_TAG_MASK) ) { 125 goto done; 126 } 127 } while ( tag <= (ber_tag_t)-1 / 256 ); 128 129 fail: 130 /* Error or unsupported tag size */ 131 tag = LBER_DEFAULT; 132 133 done: 134 bv->bv_len = rest; 135 bv->bv_val = (char *) ptr; 136 return tag; 137} 138 139/* Return the tag - LBER_DEFAULT returned means trouble */ 140ber_tag_t 141ber_get_tag( BerElement *ber ) 142{ 143 struct berval bv; 144 ber_tag_t tag = ber_tag_and_rest( ber, &bv ); 145 146 ber->ber_ptr = bv.bv_val; 147 return tag; 148} 149 150/* Return next element's tag and point *bv at its contents in-place */ 151ber_tag_t 152ber_peek_element( const BerElement *ber, struct berval *bv ) 153{ 154 ber_tag_t tag; 155 ber_len_t len, rest; 156 unsigned i; 157 unsigned char *ptr; 158 159 assert( bv != NULL ); 160 161 /* 162 * Any ber element looks like this: tag length contents. 163 * Assuming everything's ok, we return the tag, and point 164 * bv at the contents. 165 * 166 * Assumptions: 167 * 1) definite lengths 168 * 2) primitive encodings used whenever possible 169 */ 170 171 len = 0; 172 173 /* 174 * First, we read the tag. 175 */ 176 tag = ber_tag_and_rest( ber, bv ); 177 178 rest = bv->bv_len; 179 ptr = (unsigned char *) bv->bv_val; 180 if ( tag == LBER_DEFAULT || rest == 0 ) { 181 goto fail; 182 } 183 184 /* 185 * Next, read the length. The first octet determines the length 186 * of the length. If bit 8 is 0, the length is the short form, 187 * otherwise if the octet != 0x80 it's the long form, otherwise 188 * the ber element has the unsupported indefinite-length format. 189 * Lengths that do not fit in a ber_len_t are not accepted. 190 */ 191 192 len = *ptr++; 193 rest--; 194 195 if ( len & 0x80U ) { 196 len &= 0x7fU; 197 if ( len - 1U > sizeof(ber_len_t) - 1U || rest < len ) { 198 /* Indefinite-length/too long length/not enough data */ 199 goto fail; 200 } 201 202 rest -= len; 203 i = len; 204 for( len = *ptr++ & 0xffU; --i; len |= *ptr++ & 0xffU ) { 205 len <<= 8; 206 } 207 } 208 209 /* BER element should have enough data left */ 210 if( len > rest ) { 211 fail: 212 tag = LBER_DEFAULT; 213 } 214 215 bv->bv_len = len; 216 bv->bv_val = (char *) ptr; 217 return tag; 218} 219 220/* Move past next element, point *bv at it in-place, and return its tag. 221 * The caller may \0-terminate *bv, as next octet is saved in ber->ber_tag. 222 * Similar to ber_get_stringbv(ber, bv, LBER_BV_NOTERM) except on error. 223 */ 224ber_tag_t 225ber_skip_element( BerElement *ber, struct berval *bv ) 226{ 227 ber_tag_t tag = ber_peek_element( ber, bv ); 228 229 if ( tag != LBER_DEFAULT ) { 230 ber->ber_ptr = bv->bv_val + bv->bv_len; 231 ber->ber_tag = *(unsigned char *) ber->ber_ptr; 232 } 233 234 return tag; 235} 236 237ber_tag_t 238ber_peek_tag( 239 BerElement *ber, 240 ber_len_t *len ) 241{ 242 struct berval bv; 243 ber_tag_t tag = ber_peek_element( ber, &bv ); 244 245 *len = bv.bv_len; 246 return tag; 247} 248 249ber_tag_t 250ber_skip_tag( BerElement *ber, ber_len_t *lenp ) 251{ 252 struct berval bv; 253 ber_tag_t tag = ber_peek_element( ber, &bv ); 254 255 ber->ber_ptr = bv.bv_val; 256 ber->ber_tag = *(unsigned char *) ber->ber_ptr; 257 258 *lenp = bv.bv_len; 259 return tag; 260} 261 262ber_tag_t 263ber_get_int( 264 BerElement *ber, 265 ber_int_t *num ) 266{ 267 ber_tag_t tag; 268 ber_len_t len; 269 struct berval bv; 270 271 assert( num != NULL ); 272 273 tag = ber_skip_element( ber, &bv ); 274 len = bv.bv_len; 275 if ( tag == LBER_DEFAULT || len > sizeof(ber_int_t) ) { 276 return LBER_DEFAULT; 277 } 278 279 /* parse two's complement integer */ 280 if( len ) { 281 unsigned char *buf = (unsigned char *) bv.bv_val; 282 ber_len_t i; 283 ber_int_t netnum = buf[0] & 0xff; 284 285 /* sign extend */ 286 netnum = (netnum ^ 0x80) - 0x80; 287 288 /* shift in the bytes */ 289 for( i = 1; i < len; i++ ) { 290 netnum = (netnum << 8 ) | buf[i]; 291 } 292 293 *num = netnum; 294 295 } else { 296 *num = 0; 297 } 298 299 return tag; 300} 301 302ber_tag_t 303ber_get_enum( 304 BerElement *ber, 305 ber_int_t *num ) 306{ 307 return ber_get_int( ber, num ); 308} 309 310ber_tag_t 311ber_get_stringb( 312 BerElement *ber, 313 char *buf, 314 ber_len_t *len ) 315{ 316 struct berval bv; 317 ber_tag_t tag; 318 319 if ( (tag = ber_skip_element( ber, &bv )) == LBER_DEFAULT ) { 320 return LBER_DEFAULT; 321 } 322 323 /* must fit within allocated space with termination */ 324 if ( bv.bv_len >= *len ) { 325 return LBER_DEFAULT; 326 } 327 328 memcpy( buf, bv.bv_val, bv.bv_len ); 329 buf[bv.bv_len] = '\0'; 330 331 *len = bv.bv_len; 332 return tag; 333} 334 335/* Definitions for get_string vector 336 * 337 * ChArray, BvArray, and BvVec are self-explanatory. 338 * BvOff is a struct berval embedded in an array of larger structures 339 * of siz bytes at off bytes from the beginning of the struct. 340 */ 341enum bgbvc { ChArray, BvArray, BvVec, BvOff }; 342 343/* Use this single cookie for state, to keep actual 344 * stack use to the absolute minimum. 345 */ 346typedef struct bgbvr { 347 const enum bgbvc choice; 348 const int option; /* (ALLOC unless BvOff) | (STRING if ChArray) */ 349 ber_len_t siz; /* input array element size, output count */ 350 ber_len_t off; /* BvOff offset to the struct berval */ 351 void *result; 352} bgbvr; 353 354static ber_tag_t 355ber_get_stringbvl( BerElement *ber, bgbvr *b ) 356{ 357 int i = 0, n; 358 ber_tag_t tag; 359 ber_len_t tot_size = 0, siz = b->siz; 360 char *last, *orig; 361 struct berval bv, *bvp = NULL; 362 union stringbvl_u { 363 char **ca; /* ChArray */ 364 BerVarray ba; /* BvArray */ 365 struct berval **bv; /* BvVec */ 366 char *bo; /* BvOff */ 367 } res; 368 369 tag = ber_skip_tag( ber, &bv.bv_len ); 370 371 if ( tag != LBER_DEFAULT ) { 372 tag = 0; 373 orig = ber->ber_ptr; 374 last = orig + bv.bv_len; 375 376 for ( ; ber->ber_ptr < last; i++, tot_size += siz ) { 377 if ( ber_skip_element( ber, &bv ) == LBER_DEFAULT ) 378 break; 379 } 380 if ( ber->ber_ptr != last ) { 381 i = 0; 382 tag = LBER_DEFAULT; 383 } 384 385 ber->ber_ptr = orig; 386 ber->ber_tag = *(unsigned char *) orig; 387 } 388 389 b->siz = i; 390 if ( i == 0 ) { 391 return tag; 392 } 393 394 /* Allocate and NULL-terminate the result vector */ 395 b->result = ber_memalloc_x( tot_size + siz, ber->ber_memctx ); 396 if ( b->result == NULL ) { 397 return LBER_DEFAULT; 398 } 399 switch (b->choice) { 400 case ChArray: 401 res.ca = b->result; 402 res.ca[i] = NULL; 403 break; 404 case BvArray: 405 res.ba = b->result; 406 res.ba[i].bv_val = NULL; 407 break; 408 case BvVec: 409 res.bv = b->result; 410 res.bv[i] = NULL; 411 break; 412 case BvOff: 413 res.bo = (char *) b->result + b->off; 414 ((struct berval *) (res.bo + tot_size))->bv_val = NULL; 415 tot_size = 0; 416 break; 417 } 418 419 n = 0; 420 do { 421 tag = ber_get_stringbv( ber, &bv, b->option ); 422 if ( tag == LBER_DEFAULT ) { 423 goto failed; 424 } 425 426 /* store my result */ 427 switch (b->choice) { 428 case ChArray: 429 res.ca[n] = bv.bv_val; 430 break; 431 case BvArray: 432 res.ba[n] = bv; 433 break; 434 case BvVec: 435 bvp = ber_memalloc_x( sizeof( struct berval ), 436 ber->ber_memctx ); 437 if ( !bvp ) { 438 ber_memfree_x( bv.bv_val, ber->ber_memctx ); 439 goto failed; 440 } 441 res.bv[n] = bvp; 442 *bvp = bv; 443 break; 444 case BvOff: 445 *(struct berval *)(res.bo + tot_size) = bv; 446 tot_size += siz; 447 break; 448 } 449 } while (++n < i); 450 return tag; 451 452failed: 453 if (b->choice != BvOff) { /* BvOff does not have LBER_BV_ALLOC set */ 454 while (--n >= 0) { 455 switch(b->choice) { 456 case ChArray: 457 ber_memfree_x(res.ca[n], ber->ber_memctx); 458 break; 459 case BvArray: 460 ber_memfree_x(res.ba[n].bv_val, ber->ber_memctx); 461 break; 462 case BvVec: 463 ber_memfree_x(res.bv[n]->bv_val, ber->ber_memctx); 464 ber_memfree_x(res.bv[n], ber->ber_memctx); 465 break; 466 default: 467 break; 468 } 469 } 470 } 471 ber_memfree_x(b->result, ber->ber_memctx); 472 b->result = NULL; 473 return LBER_DEFAULT; 474} 475 476ber_tag_t 477ber_get_stringbv( BerElement *ber, struct berval *bv, int option ) 478{ 479 ber_tag_t tag; 480 char *data; 481 482 tag = ber_skip_element( ber, bv ); 483 if ( tag == LBER_DEFAULT || 484 (( option & LBER_BV_STRING ) && 485 bv->bv_len && memchr( bv->bv_val, 0, bv->bv_len - 1 ))) 486 { 487 bv->bv_val = NULL; 488 return LBER_DEFAULT; 489 } 490 491 data = bv->bv_val; 492 if ( option & LBER_BV_ALLOC ) { 493 bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1, 494 ber->ber_memctx ); 495 if ( bv->bv_val == NULL ) { 496 return LBER_DEFAULT; 497 } 498 499 if ( bv->bv_len != 0 ) { 500 memcpy( bv->bv_val, data, bv->bv_len ); 501 } 502 data = bv->bv_val; 503 } 504 if ( !( option & LBER_BV_NOTERM )) 505 data[bv->bv_len] = '\0'; 506 507 return tag; 508} 509 510ber_tag_t 511ber_get_stringbv_null( BerElement *ber, struct berval *bv, int option ) 512{ 513 ber_tag_t tag; 514 char *data; 515 516 tag = ber_skip_element( ber, bv ); 517 if ( tag == LBER_DEFAULT || bv->bv_len == 0 ) { 518 bv->bv_val = NULL; 519 return tag; 520 } 521 522 if (( option & LBER_BV_STRING ) && 523 memchr( bv->bv_val, 0, bv->bv_len - 1 )) 524 { 525 bv->bv_val = NULL; 526 return LBER_DEFAULT; 527 } 528 529 data = bv->bv_val; 530 if ( option & LBER_BV_ALLOC ) { 531 bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1, 532 ber->ber_memctx ); 533 if ( bv->bv_val == NULL ) { 534 return LBER_DEFAULT; 535 } 536 537 memcpy( bv->bv_val, data, bv->bv_len ); 538 data = bv->bv_val; 539 } 540 if ( !( option & LBER_BV_NOTERM )) 541 data[bv->bv_len] = '\0'; 542 543 return tag; 544} 545 546ber_tag_t 547ber_get_stringa( BerElement *ber, char **buf ) 548{ 549 BerValue bv; 550 ber_tag_t tag; 551 552 assert( buf != NULL ); 553 554 tag = ber_get_stringbv( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING ); 555 *buf = bv.bv_val; 556 557 return tag; 558} 559 560ber_tag_t 561ber_get_stringa_null( BerElement *ber, char **buf ) 562{ 563 BerValue bv; 564 ber_tag_t tag; 565 566 assert( buf != NULL ); 567 568 tag = ber_get_stringbv_null( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING ); 569 *buf = bv.bv_val; 570 571 return tag; 572} 573 574ber_tag_t 575ber_get_stringal( BerElement *ber, struct berval **bv ) 576{ 577 ber_tag_t tag; 578 579 assert( ber != NULL ); 580 assert( bv != NULL ); 581 582 *bv = (struct berval *) ber_memalloc_x( sizeof(struct berval), 583 ber->ber_memctx ); 584 if ( *bv == NULL ) { 585 return LBER_DEFAULT; 586 } 587 588 tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC ); 589 if ( tag == LBER_DEFAULT ) { 590 ber_memfree_x( *bv, ber->ber_memctx ); 591 *bv = NULL; 592 } 593 return tag; 594} 595 596ber_tag_t 597ber_get_bitstringa( 598 BerElement *ber, 599 char **buf, 600 ber_len_t *blen ) 601{ 602 ber_tag_t tag; 603 struct berval data; 604 unsigned char unusedbits; 605 606 assert( buf != NULL ); 607 assert( blen != NULL ); 608 609 if ( (tag = ber_skip_element( ber, &data )) == LBER_DEFAULT ) { 610 goto fail; 611 } 612 613 if ( --data.bv_len > (ber_len_t)-1 / 8 ) { 614 goto fail; 615 } 616 unusedbits = *(unsigned char *) data.bv_val++; 617 if ( unusedbits > 7 ) { 618 goto fail; 619 } 620 621 if ( memchr( data.bv_val, 0, data.bv_len )) { 622 goto fail; 623 } 624 625 *buf = (char *) ber_memalloc_x( data.bv_len, ber->ber_memctx ); 626 if ( *buf == NULL ) { 627 return LBER_DEFAULT; 628 } 629 memcpy( *buf, data.bv_val, data.bv_len ); 630 631 *blen = data.bv_len * 8 - unusedbits; 632 return tag; 633 634 fail: 635 *buf = NULL; 636 return LBER_DEFAULT; 637} 638 639ber_tag_t 640ber_get_null( BerElement *ber ) 641{ 642 ber_len_t len; 643 ber_tag_t tag = ber_skip_tag( ber, &len ); 644 645 return( len == 0 ? tag : LBER_DEFAULT ); 646} 647 648ber_tag_t 649ber_get_boolean( 650 BerElement *ber, 651 ber_int_t *boolval ) 652{ 653 return ber_get_int( ber, boolval ); 654} 655 656ber_tag_t 657ber_first_element( 658 BerElement *ber, 659 ber_len_t *len, 660 char **last ) 661{ 662 assert( last != NULL ); 663 664 /* skip the sequence header, use the len to mark where to stop */ 665 if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) { 666 *last = NULL; 667 return LBER_DEFAULT; 668 } 669 670 *last = ber->ber_ptr + *len; 671 672 if ( *len == 0 ) { 673 return LBER_DEFAULT; 674 } 675 676 return ber_peek_tag( ber, len ); 677} 678 679ber_tag_t 680ber_next_element( 681 BerElement *ber, 682 ber_len_t *len, 683 LDAP_CONST char *last ) 684{ 685 assert( ber != NULL ); 686 assert( last != NULL ); 687 assert( LBER_VALID( ber ) ); 688 689 if ( ber->ber_ptr >= last ) { 690 return LBER_DEFAULT; 691 } 692 693 return ber_peek_tag( ber, len ); 694} 695 696/* VARARGS */ 697ber_tag_t 698ber_scanf ( BerElement *ber, 699 LDAP_CONST char *fmt, 700 ... ) 701{ 702 va_list ap; 703 LDAP_CONST char *fmt_reset; 704 char *s, **ss, ***sss; 705 struct berval data, *bval, **bvp, ***bvpp; 706 ber_int_t *i; 707 ber_len_t *l; 708 ber_tag_t *t; 709 ber_tag_t rc; 710 ber_len_t len; 711 712 va_start( ap, fmt ); 713 714 assert( ber != NULL ); 715 assert( fmt != NULL ); 716 assert( LBER_VALID( ber ) ); 717 718 fmt_reset = fmt; 719 720 if ( ber->ber_debug & (LDAP_DEBUG_TRACE|LDAP_DEBUG_BER)) { 721 ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, 722 "ber_scanf fmt (%s) ber:\n", fmt ); 723 ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 ); 724 } 725 726 for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) { 727 /* When this is modified, remember to update 728 * the error-cleanup code below accordingly. */ 729 switch ( *fmt ) { 730 case '!': { /* Hook */ 731 BERDecodeCallback *f; 732 void *p; 733 734 f = va_arg( ap, BERDecodeCallback * ); 735 p = va_arg( ap, void * ); 736 737 rc = (*f)( ber, p, 0 ); 738 } break; 739 740 case 'a': /* octet string - allocate storage as needed */ 741 ss = va_arg( ap, char ** ); 742 rc = ber_get_stringa( ber, ss ); 743 break; 744 745 case 'A': /* octet string - allocate storage as needed, 746 * but return NULL if len == 0 */ 747 ss = va_arg( ap, char ** ); 748 rc = ber_get_stringa_null( ber, ss ); 749 break; 750 751 case 'b': /* boolean */ 752 i = va_arg( ap, ber_int_t * ); 753 rc = ber_get_boolean( ber, i ); 754 break; 755 756 case 'B': /* bit string - allocate storage as needed */ 757 ss = va_arg( ap, char ** ); 758 l = va_arg( ap, ber_len_t * ); /* for length, in bits */ 759 rc = ber_get_bitstringa( ber, ss, l ); 760 break; 761 762 case 'e': /* enumerated */ 763 case 'i': /* integer */ 764 i = va_arg( ap, ber_int_t * ); 765 rc = ber_get_int( ber, i ); 766 break; 767 768 case 'l': /* length of next item */ 769 l = va_arg( ap, ber_len_t * ); 770 rc = ber_peek_tag( ber, l ); 771 break; 772 773 case 'm': /* octet string in berval, in-place */ 774 bval = va_arg( ap, struct berval * ); 775 rc = ber_get_stringbv( ber, bval, 0 ); 776 break; 777 778 case 'M': /* bvoffarray - must include address of 779 * a record len, and record offset. 780 * number of records will be returned thru 781 * len ptr on finish. parsed in-place. 782 */ 783 { 784 bgbvr cookie = { BvOff, 0 }; 785 bvp = va_arg( ap, struct berval ** ); 786 l = va_arg( ap, ber_len_t * ); 787 cookie.siz = *l; 788 cookie.off = va_arg( ap, ber_len_t ); 789 rc = ber_get_stringbvl( ber, &cookie ); 790 *bvp = cookie.result; 791 *l = cookie.siz; 792 break; 793 } 794 795 case 'n': /* null */ 796 rc = ber_get_null( ber ); 797 break; 798 799 case 'o': /* octet string in a supplied berval */ 800 bval = va_arg( ap, struct berval * ); 801 rc = ber_get_stringbv( ber, bval, LBER_BV_ALLOC ); 802 break; 803 804 case 'O': /* octet string - allocate & include length */ 805 bvp = va_arg( ap, struct berval ** ); 806 rc = ber_get_stringal( ber, bvp ); 807 break; 808 809 case 's': /* octet string - in a buffer */ 810 s = va_arg( ap, char * ); 811 l = va_arg( ap, ber_len_t * ); 812 rc = ber_get_stringb( ber, s, l ); 813 break; 814 815 case 't': /* tag of next item */ 816 t = va_arg( ap, ber_tag_t * ); 817 *t = rc = ber_peek_tag( ber, &len ); 818 break; 819 820 case 'T': /* skip tag of next item */ 821 t = va_arg( ap, ber_tag_t * ); 822 *t = rc = ber_skip_tag( ber, &len ); 823 break; 824 825 case 'v': /* sequence of strings */ 826 { 827 bgbvr cookie = { 828 ChArray, LBER_BV_ALLOC | LBER_BV_STRING, sizeof( char * ) 829 }; 830 rc = ber_get_stringbvl( ber, &cookie ); 831 *(va_arg( ap, char *** )) = cookie.result; 832 break; 833 } 834 835 case 'V': /* sequence of strings + lengths */ 836 { 837 bgbvr cookie = { 838 BvVec, LBER_BV_ALLOC, sizeof( struct berval * ) 839 }; 840 rc = ber_get_stringbvl( ber, &cookie ); 841 *(va_arg( ap, struct berval *** )) = cookie.result; 842 break; 843 } 844 845 case 'W': /* bvarray */ 846 { 847 bgbvr cookie = { 848 BvArray, LBER_BV_ALLOC, sizeof( struct berval ) 849 }; 850 rc = ber_get_stringbvl( ber, &cookie ); 851 *(va_arg( ap, struct berval ** )) = cookie.result; 852 break; 853 } 854 855 case 'x': /* skip the next element - whatever it is */ 856 rc = ber_skip_element( ber, &data ); 857 break; 858 859 case '{': /* begin sequence */ 860 case '[': /* begin set */ 861 switch ( fmt[1] ) { 862 case 'v': case 'V': case 'W': case 'M': 863 break; 864 default: 865 rc = ber_skip_tag( ber, &len ); 866 break; 867 } 868 break; 869 870 case '}': /* end sequence */ 871 case ']': /* end set */ 872 break; 873 874 default: 875 if( ber->ber_debug ) { 876 ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, 877 "ber_scanf: unknown fmt %c\n", *fmt ); 878 } 879 rc = LBER_DEFAULT; 880 break; 881 } 882 } 883 884 va_end( ap ); 885 886 if ( rc == LBER_DEFAULT ) { 887 /* 888 * Error. Reclaim malloced memory that was given to the caller. 889 * Set allocated pointers to NULL, "data length" outvalues to 0. 890 */ 891 va_start( ap, fmt ); 892 893 for ( ; fmt_reset < fmt; fmt_reset++ ) { 894 switch ( *fmt_reset ) { 895 case '!': { /* Hook */ 896 BERDecodeCallback *f; 897 void *p; 898 899 f = va_arg( ap, BERDecodeCallback * ); 900 p = va_arg( ap, void * ); 901 902 (void) (*f)( ber, p, 1 ); 903 } break; 904 905 case 'a': /* octet string - allocate storage as needed */ 906 case 'A': 907 ss = va_arg( ap, char ** ); 908 ber_memfree_x( *ss, ber->ber_memctx ); 909 *ss = NULL; 910 break; 911 912 case 'b': /* boolean */ 913 case 'e': /* enumerated */ 914 case 'i': /* integer */ 915 (void) va_arg( ap, ber_int_t * ); 916 break; 917 918 case 'l': /* length of next item */ 919 *(va_arg( ap, ber_len_t * )) = 0; 920 break; 921 922 case 'm': /* berval in-place */ 923 bval = va_arg( ap, struct berval * ); 924 BER_BVZERO( bval ); 925 break; 926 927 case 'M': /* BVoff array in-place */ 928 bvp = va_arg( ap, struct berval ** ); 929 ber_memfree_x( *bvp, ber->ber_memctx ); 930 *bvp = NULL; 931 *(va_arg( ap, ber_len_t * )) = 0; 932 (void) va_arg( ap, ber_len_t ); 933 break; 934 935 case 'o': /* octet string in a supplied berval */ 936 bval = va_arg( ap, struct berval * ); 937 ber_memfree_x( bval->bv_val, ber->ber_memctx ); 938 BER_BVZERO( bval ); 939 break; 940 941 case 'O': /* octet string - allocate & include length */ 942 bvp = va_arg( ap, struct berval ** ); 943 ber_bvfree_x( *bvp, ber->ber_memctx ); 944 *bvp = NULL; 945 break; 946 947 case 's': /* octet string - in a buffer */ 948 (void) va_arg( ap, char * ); 949 *(va_arg( ap, ber_len_t * )) = 0; 950 break; 951 952 case 't': /* tag of next item */ 953 case 'T': /* skip tag of next item */ 954 (void) va_arg( ap, ber_tag_t * ); 955 break; 956 957 case 'B': /* bit string - allocate storage as needed */ 958 ss = va_arg( ap, char ** ); 959 ber_memfree_x( *ss, ber->ber_memctx ); 960 *ss = NULL; 961 *(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */ 962 break; 963 964 case 'v': /* sequence of strings */ 965 sss = va_arg( ap, char *** ); 966 ber_memvfree_x( (void **) *sss, ber->ber_memctx ); 967 *sss = NULL; 968 break; 969 970 case 'V': /* sequence of strings + lengths */ 971 bvpp = va_arg( ap, struct berval *** ); 972 ber_bvecfree_x( *bvpp, ber->ber_memctx ); 973 *bvpp = NULL; 974 break; 975 976 case 'W': /* BerVarray */ 977 bvp = va_arg( ap, struct berval ** ); 978 ber_bvarray_free_x( *bvp, ber->ber_memctx ); 979 *bvp = NULL; 980 break; 981 982 case 'n': /* null */ 983 case 'x': /* skip the next element - whatever it is */ 984 case '{': /* begin sequence */ 985 case '[': /* begin set */ 986 case '}': /* end sequence */ 987 case ']': /* end set */ 988 break; 989 990 default: 991 /* format should be good */ 992 assert( 0 ); 993 } 994 } 995 996 va_end( ap ); 997 } 998 999 return rc; 1000} 1001