Back to index

openldap  2.4.31
decode.c
Go to the documentation of this file.
00001 /* decode.c - ber input decoding routines */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
00017  * All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms are permitted
00020  * provided that this notice is preserved and that due credit is given
00021  * to the University of Michigan at Ann Arbor. The name of the University
00022  * may not be used to endorse or promote products derived from this
00023  * software without specific prior written permission. This software
00024  * is provided ``as is'' without express or implied warranty.
00025  */
00026 /* ACKNOWLEDGEMENTS:
00027  * This work was originally developed by the University of Michigan
00028  * (as part of U-MICH LDAP).
00029  */
00030 
00031 #include "portable.h"
00032 
00033 #include <stdio.h>
00034 
00035 #include <ac/stdlib.h>
00036 #include <ac/stdarg.h>
00037 #include <ac/string.h>
00038 #include <ac/socket.h>
00039 
00040 #include "lber-int.h"
00041 
00042 
00043 /* out->bv_len should be the buffer size on input */
00044 int
00045 ber_decode_oid( BerValue *in, BerValue *out )
00046 {
00047        const unsigned char *der;
00048        unsigned long val;
00049        unsigned val1;
00050        ber_len_t i;
00051        char *ptr;
00052 
00053        assert( in != NULL );
00054        assert( out != NULL );
00055 
00056        /* need 4 chars/inbyte + \0 for input={7f 7f 7f...} */
00057        if ( !out->bv_val || (out->bv_len+3)/4 <= in->bv_len )
00058               return -1;
00059 
00060        ptr = NULL;
00061        der = (unsigned char *) in->bv_val;
00062        val = 0;
00063        for ( i=0; i < in->bv_len; i++ ) {
00064               val |= der[i] & 0x7f;
00065               if ( !( der[i] & 0x80 )) {
00066                      if ( ptr == NULL ) {
00067                             /* Initial "x.y": val=x*40+y, x<=2, y<40 if x<2 */
00068                             ptr = out->bv_val;
00069                             val1 = (val < 80 ? val/40 : 2);
00070                             val -= val1*40;
00071                             ptr += sprintf( ptr, "%u", val1 );
00072                      }
00073                      ptr += sprintf( ptr, ".%lu", val );
00074                      val = 0;
00075               } else if ( val - 1UL < LBER_OID_COMPONENT_MAX >> 7 ) {
00076                      val <<= 7;
00077               } else {
00078                      /* val would overflow, or is 0 from invalid initial 0x80 octet */
00079                      return -1;
00080               }
00081        }
00082        if ( ptr == NULL || val != 0 )
00083               return -1;
00084 
00085        out->bv_len = ptr - out->bv_val;
00086        return 0;
00087 }
00088 
00089 /* Return tag, with *bv = rest of element (starting at length octets) */
00090 static ber_tag_t
00091 ber_tag_and_rest( const BerElement *ber, struct berval *bv )
00092 {
00093        ber_tag_t     tag;
00094        ptrdiff_t     rest;
00095        unsigned char *ptr;
00096 
00097        assert( ber != NULL );
00098        assert( LBER_VALID( ber ) );
00099 
00100        ptr = (unsigned char *) ber->ber_ptr;
00101        rest = (unsigned char *) ber->ber_end - ptr;
00102        if ( rest <= 0 ) {
00103               goto fail;
00104        }
00105 
00106        tag = ber->ber_tag;
00107        if ( (char *) ptr == ber->ber_buf ) {
00108               tag = *ptr;
00109        }
00110        ptr++;
00111        rest--;
00112        if ( (tag & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
00113               goto done;
00114        }
00115 
00116        do {
00117               if ( rest <= 0 ) {
00118                      break;
00119               }
00120               tag <<= 8;
00121               tag |= *ptr++ & 0xffU;
00122               rest--;
00123 
00124               if ( ! (tag & LBER_MORE_TAG_MASK) ) {
00125                      goto done;
00126               }
00127        } while ( tag <= (ber_tag_t)-1 / 256 );
00128 
00129  fail:
00130        /* Error or unsupported tag size */
00131        tag = LBER_DEFAULT;
00132 
00133  done:
00134        bv->bv_len = rest;
00135        bv->bv_val = (char *) ptr;
00136        return tag;
00137 }
00138 
00139 /* Return the tag - LBER_DEFAULT returned means trouble */
00140 ber_tag_t
00141 ber_get_tag( BerElement *ber )
00142 {
00143        struct berval bv;
00144        ber_tag_t tag = ber_tag_and_rest( ber, &bv );
00145 
00146        ber->ber_ptr = bv.bv_val;
00147        return tag;
00148 }
00149 
00150 /* Return next element's tag and point *bv at its contents in-place */
00151 ber_tag_t
00152 ber_peek_element( const BerElement *ber, struct berval *bv )
00153 {
00154        ber_tag_t     tag;
00155        ber_len_t     len, rest;
00156        unsigned      i;
00157        unsigned char *ptr;
00158 
00159        assert( bv != NULL );
00160 
00161        /*
00162         * Any ber element looks like this: tag length contents.
00163         * Assuming everything's ok, we return the tag, and point
00164         * bv at the contents.
00165         *
00166         * Assumptions:
00167         *     1) definite lengths
00168         *     2) primitive encodings used whenever possible
00169         */
00170 
00171        len = 0;
00172 
00173        /*
00174         * First, we read the tag.
00175         */
00176        tag = ber_tag_and_rest( ber, bv );
00177 
00178        rest = bv->bv_len;
00179        ptr = (unsigned char *) bv->bv_val;
00180        if ( tag == LBER_DEFAULT || rest == 0 ) {
00181               goto fail;
00182        }
00183 
00184        /*
00185         * Next, read the length.  The first octet determines the length
00186         * of the length.    If bit 8 is 0, the length is the short form,
00187         * otherwise if the octet != 0x80 it's the long form, otherwise
00188         * the ber element has the unsupported indefinite-length format.
00189         * Lengths that do not fit in a ber_len_t are not accepted.
00190         */
00191 
00192        len = *ptr++;
00193        rest--;
00194 
00195        if ( len & 0x80U ) {
00196               len &= 0x7fU;
00197               if ( len - 1U > sizeof(ber_len_t) - 1U || rest < len ) {
00198                      /* Indefinite-length/too long length/not enough data */
00199                      goto fail;
00200               }
00201 
00202               rest -= len;
00203               i = len;
00204               for( len = *ptr++ & 0xffU; --i; len |= *ptr++ & 0xffU ) {
00205                      len <<= 8;
00206               }
00207        }
00208 
00209        /* BER element should have enough data left */
00210        if( len > rest ) {
00211        fail:
00212               tag = LBER_DEFAULT;
00213        }
00214 
00215        bv->bv_len = len;
00216        bv->bv_val = (char *) ptr;
00217        return tag;
00218 }
00219 
00220 /* Move past next element, point *bv at it in-place, and return its tag.
00221  * The caller may \0-terminate *bv, as next octet is saved in ber->ber_tag.
00222  * Similar to ber_get_stringbv(ber, bv, LBER_BV_NOTERM) except on error.
00223  */
00224 ber_tag_t
00225 ber_skip_element( BerElement *ber, struct berval *bv )
00226 {
00227        ber_tag_t tag = ber_peek_element( ber, bv );
00228 
00229        if ( tag != LBER_DEFAULT ) {
00230               ber->ber_ptr = bv->bv_val + bv->bv_len;
00231               ber->ber_tag = *(unsigned char *) ber->ber_ptr;
00232        }
00233 
00234        return tag;
00235 }
00236 
00237 ber_tag_t
00238 ber_peek_tag(
00239        BerElement *ber,
00240        ber_len_t *len )
00241 {
00242        struct berval bv;
00243        ber_tag_t tag = ber_peek_element( ber, &bv );
00244 
00245        *len = bv.bv_len;
00246        return tag;
00247 }
00248 
00249 ber_tag_t
00250 ber_skip_tag( BerElement *ber, ber_len_t *lenp )
00251 {
00252        struct berval bv;
00253        ber_tag_t tag = ber_peek_element( ber, &bv );
00254 
00255        ber->ber_ptr = bv.bv_val;
00256        ber->ber_tag = *(unsigned char *) ber->ber_ptr;
00257 
00258        *lenp = bv.bv_len;
00259        return tag;
00260 }
00261 
00262 ber_tag_t
00263 ber_get_int(
00264        BerElement *ber,
00265        ber_int_t *num )
00266 {
00267        ber_tag_t     tag;
00268        ber_len_t     len;
00269        struct berval bv;
00270 
00271        assert( num != NULL );
00272 
00273        tag = ber_skip_element( ber, &bv );
00274        len = bv.bv_len;
00275        if ( tag == LBER_DEFAULT || len > sizeof(ber_int_t) ) {
00276               return LBER_DEFAULT;
00277        }
00278 
00279        /* parse two's complement integer */
00280        if( len ) {
00281               unsigned char *buf = (unsigned char *) bv.bv_val;
00282               ber_len_t i;
00283               ber_int_t netnum = buf[0] & 0xff;
00284 
00285               /* sign extend */
00286               netnum = (netnum ^ 0x80) - 0x80;
00287 
00288               /* shift in the bytes */
00289               for( i = 1; i < len; i++ ) {
00290                      netnum = (netnum << 8 ) | buf[i];
00291               }
00292 
00293               *num = netnum;
00294 
00295        } else {
00296               *num = 0;
00297        }
00298 
00299        return tag;
00300 }
00301 
00302 ber_tag_t
00303 ber_get_enum(
00304        BerElement *ber,
00305        ber_int_t *num )
00306 {
00307        return ber_get_int( ber, num );
00308 }
00309 
00310 ber_tag_t
00311 ber_get_stringb(
00312        BerElement *ber,
00313        char *buf,
00314        ber_len_t *len )
00315 {
00316        struct berval bv;
00317        ber_tag_t     tag;
00318 
00319        if ( (tag = ber_skip_element( ber, &bv )) == LBER_DEFAULT ) {
00320               return LBER_DEFAULT;
00321        }
00322 
00323        /* must fit within allocated space with termination */
00324        if ( bv.bv_len >= *len ) {
00325               return LBER_DEFAULT;
00326        }
00327 
00328        memcpy( buf, bv.bv_val, bv.bv_len );
00329        buf[bv.bv_len] = '\0';
00330 
00331        *len = bv.bv_len;
00332        return tag;
00333 }
00334 
00335 /* Definitions for get_string vector
00336  *
00337  * ChArray, BvArray, and BvVec are self-explanatory.
00338  * BvOff is a struct berval embedded in an array of larger structures
00339  * of siz bytes at off bytes from the beginning of the struct.
00340  */
00341 enum bgbvc { ChArray, BvArray, BvVec, BvOff };
00342 
00343 /* Use this single cookie for state, to keep actual
00344  * stack use to the absolute minimum.
00345  */
00346 typedef struct bgbvr {
00347        const enum bgbvc choice;
00348        const int option;    /* (ALLOC unless BvOff) | (STRING if ChArray) */
00349        ber_len_t siz;              /* input array element size, output count */
00350        ber_len_t off;              /* BvOff offset to the struct berval */
00351        void *result;
00352 } bgbvr;
00353 
00354 static ber_tag_t
00355 ber_get_stringbvl( BerElement *ber, bgbvr *b )
00356 {
00357        int i = 0, n;
00358        ber_tag_t tag;
00359        ber_len_t tot_size = 0, siz = b->siz;
00360        char *last, *orig;
00361        struct berval bv, *bvp = NULL;
00362        union stringbvl_u {
00363               char **ca;                         /* ChArray */
00364               BerVarray ba;               /* BvArray */
00365               struct berval **bv;         /* BvVec */
00366               char *bo;                          /* BvOff */
00367        } res;
00368 
00369        tag = ber_skip_tag( ber, &bv.bv_len );
00370 
00371        if ( tag != LBER_DEFAULT ) {
00372               tag = 0;
00373               orig = ber->ber_ptr;
00374               last = orig + bv.bv_len;
00375 
00376               for ( ; ber->ber_ptr < last; i++, tot_size += siz ) {
00377                      if ( ber_skip_element( ber, &bv ) == LBER_DEFAULT )
00378                             break;
00379               }
00380               if ( ber->ber_ptr != last ) {
00381                      i = 0;
00382                      tag = LBER_DEFAULT;
00383               }
00384 
00385               ber->ber_ptr = orig;
00386               ber->ber_tag = *(unsigned char *) orig;
00387        }
00388 
00389        b->siz = i;
00390        if ( i == 0 ) {
00391               return tag;
00392        }
00393 
00394        /* Allocate and NULL-terminate the result vector */
00395        b->result = ber_memalloc_x( tot_size + siz, ber->ber_memctx );
00396        if ( b->result == NULL ) {
00397               return LBER_DEFAULT;
00398        }
00399        switch (b->choice) {
00400        case ChArray:
00401               res.ca = b->result;
00402               res.ca[i] = NULL;
00403               break;
00404        case BvArray:
00405               res.ba = b->result;
00406               res.ba[i].bv_val = NULL;
00407               break;
00408        case BvVec:
00409               res.bv = b->result;
00410               res.bv[i] = NULL;
00411               break;
00412        case BvOff:
00413               res.bo = (char *) b->result + b->off;
00414               ((struct berval *) (res.bo + tot_size))->bv_val = NULL;
00415               tot_size = 0;
00416               break;
00417        }
00418 
00419        n = 0;
00420        do {
00421               tag = ber_get_stringbv( ber, &bv, b->option );
00422               if ( tag == LBER_DEFAULT ) {
00423                      goto failed;
00424               }
00425 
00426               /* store my result */
00427               switch (b->choice) {
00428               case ChArray:
00429                      res.ca[n] = bv.bv_val;
00430                      break;
00431               case BvArray:
00432                      res.ba[n] = bv;
00433                      break;
00434               case BvVec:
00435                      bvp = ber_memalloc_x( sizeof( struct berval ),
00436                             ber->ber_memctx );
00437                      if ( !bvp ) {
00438                             ber_memfree_x( bv.bv_val, ber->ber_memctx );
00439                             goto failed;
00440                      }
00441                      res.bv[n] = bvp;
00442                      *bvp = bv;
00443                      break;
00444               case BvOff:
00445                      *(struct berval *)(res.bo + tot_size) = bv;
00446                      tot_size += siz;
00447                      break;
00448               }
00449        } while (++n < i);
00450        return tag;
00451 
00452 failed:
00453        if (b->choice != BvOff) { /* BvOff does not have LBER_BV_ALLOC set */
00454               while (--n >= 0) {
00455                      switch(b->choice) {
00456                      case ChArray:
00457                             ber_memfree_x(res.ca[n], ber->ber_memctx);
00458                             break;
00459                      case BvArray:
00460                             ber_memfree_x(res.ba[n].bv_val, ber->ber_memctx);
00461                             break;
00462                      case BvVec:
00463                             ber_memfree_x(res.bv[n]->bv_val, ber->ber_memctx);
00464                             ber_memfree_x(res.bv[n], ber->ber_memctx);
00465                             break;
00466                      default:
00467                             break;
00468                      }
00469               }
00470        }
00471        ber_memfree_x(b->result, ber->ber_memctx);
00472        b->result = NULL;
00473        return LBER_DEFAULT;
00474 }
00475 
00476 ber_tag_t
00477 ber_get_stringbv( BerElement *ber, struct berval *bv, int option )
00478 {
00479        ber_tag_t     tag;
00480        char          *data;
00481 
00482        tag = ber_skip_element( ber, bv );
00483        if ( tag == LBER_DEFAULT ||
00484               (( option & LBER_BV_STRING ) &&
00485                bv->bv_len && memchr( bv->bv_val, 0, bv->bv_len - 1 )))
00486        {
00487               bv->bv_val = NULL;
00488               return LBER_DEFAULT;
00489        }
00490 
00491        data = bv->bv_val;
00492        if ( option & LBER_BV_ALLOC ) {
00493               bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
00494                      ber->ber_memctx );
00495               if ( bv->bv_val == NULL ) {
00496                      return LBER_DEFAULT;
00497               }
00498 
00499               if ( bv->bv_len != 0 ) {
00500                      memcpy( bv->bv_val, data, bv->bv_len );
00501               }
00502               data = bv->bv_val;
00503        }
00504        if ( !( option & LBER_BV_NOTERM ))
00505               data[bv->bv_len] = '\0';
00506 
00507        return tag;
00508 }
00509 
00510 ber_tag_t
00511 ber_get_stringbv_null( BerElement *ber, struct berval *bv, int option )
00512 {
00513        ber_tag_t     tag;
00514        char          *data;
00515 
00516        tag = ber_skip_element( ber, bv );
00517        if ( tag == LBER_DEFAULT || bv->bv_len == 0 ) {
00518               bv->bv_val = NULL;
00519               return tag;
00520        }
00521 
00522        if (( option & LBER_BV_STRING ) &&
00523               memchr( bv->bv_val, 0, bv->bv_len - 1 ))
00524        {
00525               bv->bv_val = NULL;
00526               return LBER_DEFAULT;
00527        }
00528 
00529        data = bv->bv_val;
00530        if ( option & LBER_BV_ALLOC ) {
00531               bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
00532                      ber->ber_memctx );
00533               if ( bv->bv_val == NULL ) {
00534                      return LBER_DEFAULT;
00535               }
00536 
00537               memcpy( bv->bv_val, data, bv->bv_len );
00538               data = bv->bv_val;
00539        }
00540        if ( !( option & LBER_BV_NOTERM ))
00541               data[bv->bv_len] = '\0';
00542 
00543        return tag;
00544 }
00545 
00546 ber_tag_t
00547 ber_get_stringa( BerElement *ber, char **buf )
00548 {
00549        BerValue      bv;
00550        ber_tag_t     tag;
00551 
00552        assert( buf != NULL );
00553 
00554        tag = ber_get_stringbv( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING );
00555        *buf = bv.bv_val;
00556 
00557        return tag;
00558 }
00559 
00560 ber_tag_t
00561 ber_get_stringa_null( BerElement *ber, char **buf )
00562 {
00563        BerValue      bv;
00564        ber_tag_t     tag;
00565 
00566        assert( buf != NULL );
00567 
00568        tag = ber_get_stringbv_null( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING );
00569        *buf = bv.bv_val;
00570 
00571        return tag;
00572 }
00573 
00574 ber_tag_t
00575 ber_get_stringal( BerElement *ber, struct berval **bv )
00576 {
00577        ber_tag_t     tag;
00578 
00579        assert( ber != NULL );
00580        assert( bv != NULL );
00581 
00582        *bv = (struct berval *) ber_memalloc_x( sizeof(struct berval),
00583               ber->ber_memctx );
00584        if ( *bv == NULL ) {
00585               return LBER_DEFAULT;
00586        }
00587 
00588        tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC );
00589        if ( tag == LBER_DEFAULT ) {
00590               ber_memfree_x( *bv, ber->ber_memctx );
00591               *bv = NULL;
00592        }
00593        return tag;
00594 }
00595 
00596 ber_tag_t
00597 ber_get_bitstringa(
00598        BerElement *ber,
00599        char **buf,
00600        ber_len_t *blen )
00601 {
00602        ber_tag_t     tag;
00603        struct berval data;
00604        unsigned char unusedbits;
00605 
00606        assert( buf != NULL );
00607        assert( blen != NULL );
00608 
00609        if ( (tag = ber_skip_element( ber, &data )) == LBER_DEFAULT ) {
00610               goto fail;
00611        }
00612 
00613        if ( --data.bv_len > (ber_len_t)-1 / 8 ) {
00614               goto fail;
00615        }
00616        unusedbits = *(unsigned char *) data.bv_val++;
00617        if ( unusedbits > 7 ) {
00618               goto fail;
00619        }
00620 
00621        if ( memchr( data.bv_val, 0, data.bv_len )) {
00622               goto fail;
00623        }
00624 
00625        *buf = (char *) ber_memalloc_x( data.bv_len, ber->ber_memctx );
00626        if ( *buf == NULL ) {
00627               return LBER_DEFAULT;
00628        }
00629        memcpy( *buf, data.bv_val, data.bv_len );
00630 
00631        *blen = data.bv_len * 8 - unusedbits;
00632        return tag;
00633 
00634  fail:
00635        *buf = NULL;
00636        return LBER_DEFAULT;
00637 }
00638 
00639 ber_tag_t
00640 ber_get_null( BerElement *ber )
00641 {
00642        ber_len_t     len;
00643        ber_tag_t     tag = ber_skip_tag( ber, &len );
00644 
00645        return( len == 0 ? tag : LBER_DEFAULT );
00646 }
00647 
00648 ber_tag_t
00649 ber_get_boolean(
00650        BerElement *ber,
00651        ber_int_t *boolval )
00652 {
00653        return ber_get_int( ber, boolval );
00654 }
00655 
00656 ber_tag_t
00657 ber_first_element(
00658        BerElement *ber,
00659        ber_len_t *len,
00660        char **last )
00661 {
00662        assert( last != NULL );
00663 
00664        /* skip the sequence header, use the len to mark where to stop */
00665        if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
00666               *last = NULL;
00667               return LBER_DEFAULT;
00668        }
00669 
00670        *last = ber->ber_ptr + *len;
00671 
00672        if ( *len == 0 ) {
00673               return LBER_DEFAULT;
00674        }
00675 
00676        return ber_peek_tag( ber, len );
00677 }
00678 
00679 ber_tag_t
00680 ber_next_element(
00681        BerElement *ber,
00682        ber_len_t *len,
00683        LDAP_CONST char *last )
00684 {
00685        assert( ber != NULL );
00686        assert( last != NULL );
00687        assert( LBER_VALID( ber ) );
00688 
00689        if ( ber->ber_ptr >= last ) {
00690               return LBER_DEFAULT;
00691        }
00692 
00693        return ber_peek_tag( ber, len );
00694 }
00695 
00696 /* VARARGS */
00697 ber_tag_t
00698 ber_scanf ( BerElement *ber,
00699        LDAP_CONST char *fmt,
00700        ... )
00701 {
00702        va_list              ap;
00703        LDAP_CONST char             *fmt_reset;
00704        char          *s, **ss, ***sss;
00705        struct berval data, *bval, **bvp, ***bvpp;
00706        ber_int_t     *i;
00707        ber_len_t     *l;
00708        ber_tag_t     *t;
00709        ber_tag_t     rc;
00710        ber_len_t     len;
00711 
00712        va_start( ap, fmt );
00713 
00714        assert( ber != NULL );
00715        assert( fmt != NULL );
00716        assert( LBER_VALID( ber ) );
00717 
00718        fmt_reset = fmt;
00719 
00720        if ( ber->ber_debug & (LDAP_DEBUG_TRACE|LDAP_DEBUG_BER)) {
00721               ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
00722                      "ber_scanf fmt (%s) ber:\n", fmt );
00723               ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
00724        }
00725 
00726        for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) {
00727               /* When this is modified, remember to update
00728                * the error-cleanup code below accordingly. */
00729               switch ( *fmt ) {
00730               case '!': { /* Hook */
00731                             BERDecodeCallback *f;
00732                             void *p;
00733 
00734                             f = va_arg( ap, BERDecodeCallback * );
00735                             p = va_arg( ap, void * );
00736 
00737                             rc = (*f)( ber, p, 0 );
00738                      } break;
00739 
00740               case 'a':     /* octet string - allocate storage as needed */
00741                      ss = va_arg( ap, char ** );
00742                      rc = ber_get_stringa( ber, ss );
00743                      break;
00744 
00745               case 'A':     /* octet string - allocate storage as needed,
00746                              * but return NULL if len == 0 */
00747                      ss = va_arg( ap, char ** );
00748                      rc = ber_get_stringa_null( ber, ss );
00749                      break;
00750 
00751               case 'b':     /* boolean */
00752                      i = va_arg( ap, ber_int_t * );
00753                      rc = ber_get_boolean( ber, i );
00754                      break;
00755 
00756               case 'B':     /* bit string - allocate storage as needed */
00757                      ss = va_arg( ap, char ** );
00758                      l = va_arg( ap, ber_len_t * ); /* for length, in bits */
00759                      rc = ber_get_bitstringa( ber, ss, l );
00760                      break;
00761 
00762               case 'e':     /* enumerated */
00763               case 'i':     /* integer */
00764                      i = va_arg( ap, ber_int_t * );
00765                      rc = ber_get_int( ber, i );
00766                      break;
00767 
00768               case 'l':     /* length of next item */
00769                      l = va_arg( ap, ber_len_t * );
00770                      rc = ber_peek_tag( ber, l );
00771                      break;
00772 
00773               case 'm':     /* octet string in berval, in-place */
00774                      bval = va_arg( ap, struct berval * );
00775                      rc = ber_get_stringbv( ber, bval, 0 );
00776                      break;
00777 
00778               case 'M':     /* bvoffarray - must include address of
00779                              * a record len, and record offset.
00780                              * number of records will be returned thru
00781                              * len ptr on finish. parsed in-place.
00782                              */
00783               {
00784                      bgbvr cookie = { BvOff, 0 };
00785                      bvp = va_arg( ap, struct berval ** );
00786                      l = va_arg( ap, ber_len_t * );
00787                      cookie.siz = *l;
00788                      cookie.off = va_arg( ap, ber_len_t );
00789                      rc = ber_get_stringbvl( ber, &cookie );
00790                      *bvp = cookie.result;
00791                      *l = cookie.siz;
00792                      break;
00793               }
00794 
00795               case 'n':     /* null */
00796                      rc = ber_get_null( ber );
00797                      break;
00798 
00799               case 'o':     /* octet string in a supplied berval */
00800                      bval = va_arg( ap, struct berval * );
00801                      rc = ber_get_stringbv( ber, bval, LBER_BV_ALLOC );
00802                      break;
00803 
00804               case 'O':     /* octet string - allocate & include length */
00805                      bvp = va_arg( ap, struct berval ** );
00806                      rc = ber_get_stringal( ber, bvp );
00807                      break;
00808 
00809               case 's':     /* octet string - in a buffer */
00810                      s = va_arg( ap, char * );
00811                      l = va_arg( ap, ber_len_t * );
00812                      rc = ber_get_stringb( ber, s, l );
00813                      break;
00814 
00815               case 't':     /* tag of next item */
00816                      t = va_arg( ap, ber_tag_t * );
00817                      *t = rc = ber_peek_tag( ber, &len );
00818                      break;
00819 
00820               case 'T':     /* skip tag of next item */
00821                      t = va_arg( ap, ber_tag_t * );
00822                      *t = rc = ber_skip_tag( ber, &len );
00823                      break;
00824 
00825               case 'v':     /* sequence of strings */
00826               {
00827                      bgbvr cookie = {
00828                             ChArray, LBER_BV_ALLOC | LBER_BV_STRING, sizeof( char * )
00829                      };
00830                      rc = ber_get_stringbvl( ber, &cookie );
00831                      *(va_arg( ap, char *** )) = cookie.result;
00832                      break;
00833               }
00834 
00835               case 'V':     /* sequence of strings + lengths */
00836               {
00837                      bgbvr cookie = {
00838                             BvVec, LBER_BV_ALLOC, sizeof( struct berval * )
00839                      };
00840                      rc = ber_get_stringbvl( ber, &cookie );
00841                      *(va_arg( ap, struct berval *** )) = cookie.result;
00842                      break;
00843               }
00844 
00845               case 'W':     /* bvarray */
00846               {
00847                      bgbvr cookie = {
00848                             BvArray, LBER_BV_ALLOC, sizeof( struct berval )
00849                      };
00850                      rc = ber_get_stringbvl( ber, &cookie );
00851                      *(va_arg( ap, struct berval ** )) = cookie.result;
00852                      break;
00853               }
00854 
00855               case 'x':     /* skip the next element - whatever it is */
00856                      rc = ber_skip_element( ber, &data );
00857                      break;
00858 
00859               case '{':     /* begin sequence */
00860               case '[':     /* begin set */
00861                      switch ( fmt[1] ) {
00862                      case 'v': case 'V': case 'W': case 'M':
00863                             break;
00864                      default:
00865                             rc = ber_skip_tag( ber, &len );
00866                             break;
00867                      }
00868                      break;
00869 
00870               case '}':     /* end sequence */
00871               case ']':     /* end set */
00872                      break;
00873 
00874               default:
00875                      if( ber->ber_debug ) {
00876                             ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
00877                                    "ber_scanf: unknown fmt %c\n", *fmt );
00878                      }
00879                      rc = LBER_DEFAULT;
00880                      break;
00881               }
00882        }
00883 
00884        va_end( ap );
00885 
00886        if ( rc == LBER_DEFAULT ) {
00887               /*
00888                * Error.  Reclaim malloced memory that was given to the caller.
00889                * Set allocated pointers to NULL, "data length" outvalues to 0.
00890                */
00891               va_start( ap, fmt );
00892 
00893               for ( ; fmt_reset < fmt; fmt_reset++ ) {
00894               switch ( *fmt_reset ) {
00895               case '!': { /* Hook */
00896                             BERDecodeCallback *f;
00897                             void *p;
00898 
00899                             f = va_arg( ap, BERDecodeCallback * );
00900                             p = va_arg( ap, void * );
00901 
00902                             (void) (*f)( ber, p, 1 );
00903                      } break;
00904 
00905               case 'a':     /* octet string - allocate storage as needed */
00906               case 'A':
00907                      ss = va_arg( ap, char ** );
00908                      ber_memfree_x( *ss, ber->ber_memctx );
00909                      *ss = NULL;
00910                      break;
00911 
00912               case 'b':     /* boolean */
00913               case 'e':     /* enumerated */
00914               case 'i':     /* integer */
00915                      (void) va_arg( ap, ber_int_t * );
00916                      break;
00917 
00918               case 'l':     /* length of next item */
00919                      *(va_arg( ap, ber_len_t * )) = 0;
00920                      break;
00921 
00922               case 'm':     /* berval in-place */
00923                      bval = va_arg( ap, struct berval * );
00924                      BER_BVZERO( bval );
00925                      break;
00926 
00927               case 'M':     /* BVoff array in-place */
00928                      bvp = va_arg( ap, struct berval ** );
00929                      ber_memfree_x( *bvp, ber->ber_memctx );
00930                      *bvp = NULL;
00931                      *(va_arg( ap, ber_len_t * )) = 0;
00932                      (void) va_arg( ap, ber_len_t );
00933                      break;
00934 
00935               case 'o':     /* octet string in a supplied berval */
00936                      bval = va_arg( ap, struct berval * );
00937                      ber_memfree_x( bval->bv_val, ber->ber_memctx );
00938                      BER_BVZERO( bval );
00939                      break;
00940 
00941               case 'O':     /* octet string - allocate & include length */
00942                      bvp = va_arg( ap, struct berval ** );
00943                      ber_bvfree_x( *bvp, ber->ber_memctx );
00944                      *bvp = NULL;
00945                      break;
00946 
00947               case 's':     /* octet string - in a buffer */
00948                      (void) va_arg( ap, char * );
00949                      *(va_arg( ap, ber_len_t * )) = 0;
00950                      break;
00951 
00952               case 't':     /* tag of next item */
00953               case 'T':     /* skip tag of next item */
00954                      (void) va_arg( ap, ber_tag_t * );
00955                      break;
00956 
00957               case 'B':     /* bit string - allocate storage as needed */
00958                      ss = va_arg( ap, char ** );
00959                      ber_memfree_x( *ss, ber->ber_memctx );
00960                      *ss = NULL;
00961                      *(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */
00962                      break;
00963 
00964               case 'v':     /* sequence of strings */
00965                      sss = va_arg( ap, char *** );
00966                      ber_memvfree_x( (void **) *sss, ber->ber_memctx );
00967                      *sss = NULL;
00968                      break;
00969 
00970               case 'V':     /* sequence of strings + lengths */
00971                      bvpp = va_arg( ap, struct berval *** );
00972                      ber_bvecfree_x( *bvpp, ber->ber_memctx );
00973                      *bvpp = NULL;
00974                      break;
00975 
00976               case 'W':     /* BerVarray */
00977                      bvp = va_arg( ap, struct berval ** );
00978                      ber_bvarray_free_x( *bvp, ber->ber_memctx );
00979                      *bvp = NULL;
00980                      break;
00981 
00982               case 'n':     /* null */
00983               case 'x':     /* skip the next element - whatever it is */
00984               case '{':     /* begin sequence */
00985               case '[':     /* begin set */
00986               case '}':     /* end sequence */
00987               case ']':     /* end set */
00988                      break;
00989 
00990               default:
00991                      /* format should be good */
00992                      assert( 0 );
00993               }
00994               }
00995 
00996               va_end( ap );
00997        }
00998 
00999        return rc;
01000 }