--- libraries/liblber/decode.c 2009/08/02 21:06:33 1.105.2.7 +++ libraries/liblber/decode.c 2007/03/23 14:27:38 1.108 @@ -1,8 +1,8 @@ /* decode.c - ber input decoding routines */ -/* $OpenLDAP: pkg/ldap/libraries/liblber/decode.c,v 1.105.2.6 2009/01/22 00:00:53 kurt Exp $ */ +/* $OpenLDAP: pkg/ldap/libraries/liblber/decode.c,v 1.107 2007/03/20 14:10:16 hyc Exp $ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2009 The OpenLDAP Foundation. + * Copyright 1998-2007 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,55 +33,48 @@ #include #include + #include #include #include #include "lber-int.h" +static ber_len_t ber_getnint LDAP_P(( + BerElement *ber, + ber_int_t *num, + ber_len_t len )); /* out->bv_len should be the buffer size on input */ int ber_decode_oid( BerValue *in, BerValue *out ) { - const unsigned char *der; - unsigned long val; - unsigned val1; - ber_len_t i; + unsigned char *der = in->bv_val; + unsigned long val, val1; + int i, len; char *ptr; assert( in != NULL ); assert( out != NULL ); - /* need 4 chars/inbyte + \0 for input={7f 7f 7f...} */ - if ( !out->bv_val || (out->bv_len+3)/4 <= in->bv_len ) + /* expands by 5/2, and we add dots - call it 3 */ + if ( !out->bv_val || out->bv_len < in->bv_len * 3 ) return -1; - ptr = NULL; - der = (unsigned char *) in->bv_val; + val1 = der[0] / 40; + val = der[0] - val1 * 40; + + len = sprintf( out->bv_val, "%ld.%ld", val1, val ); + ptr = out->bv_val + len; val = 0; - for ( i=0; i < in->bv_len; i++ ) { + for ( i=1; ibv_len; i++ ) { + val = val << 7; val |= der[i] & 0x7f; if ( !( der[i] & 0x80 )) { - if ( ptr == NULL ) { - /* Initial "x.y": val=x*40+y, x<=2, y<40 if x<2 */ - ptr = out->bv_val; - val1 = (val < 80 ? val/40 : 2); - val -= val1*40; - ptr += sprintf( ptr, "%u", val1 ); - } - ptr += sprintf( ptr, ".%lu", val ); + ptr += sprintf( ptr, ".%ld", val ); val = 0; - } else if ( val - 1UL < LBER_OID_COMPONENT_MAX >> 7 ) { - val <<= 7; - } else { - /* val would overflow, or is 0 from invalid initial 0x80 octet */ - return -1; } } - if ( ptr == NULL || val != 0 ) - return -1; - out->bv_len = ptr - out->bv_val; return 0; } @@ -92,6 +85,7 @@ ber_get_tag( BerElement *ber ) { unsigned char xbyte; ber_tag_t tag; + unsigned int i; assert( ber != NULL ); assert( LBER_VALID( ber ) ); @@ -111,44 +105,50 @@ ber_get_tag( BerElement *ber ) return tag; } - do { + for ( i = 1; i < sizeof(ber_tag_t); i++ ) { if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 ) { - break; + return LBER_DEFAULT; } tag <<= 8; tag |= 0x00ffUL & (ber_tag_t) xbyte; if ( ! (xbyte & LBER_MORE_TAG_MASK) ) { - return tag; + break; } - } while ( tag <= (ber_tag_t)-1 / 256 ); + } - return LBER_DEFAULT; /* error or tag too big */ + /* tag too big! */ + if ( i == sizeof(ber_tag_t) ) { + return LBER_DEFAULT; + } + + return tag; } ber_tag_t -ber_skip_tag( BerElement *ber, ber_len_t *lenp ) +ber_skip_tag( BerElement *ber, ber_len_t *len ) { ber_tag_t tag; - ber_len_t len; - unsigned i, noctets; unsigned char lc; + ber_len_t i, noctets; unsigned char netlen[sizeof(ber_len_t)]; - assert( lenp != NULL ); + assert( ber != NULL ); + assert( len != NULL ); + assert( LBER_VALID( ber ) ); /* * Any ber element looks like this: tag length contents. * Assuming everything's ok, we return the tag byte (we - * can assume a single byte), and return the length in lenp. + * can assume a single byte), and return the length in len. * * Assumptions: * 1) definite lengths * 2) primitive encodings used whenever possible */ - *lenp = 0; + *len = 0; /* * First, we read the tag. @@ -159,23 +159,20 @@ ber_skip_tag( BerElement *ber, ber_len_t } /* - * Next, read the length. The first octet determines the length - * of the length. If bit 8 is 0, the length is the short form, - * otherwise if the octet != 0x80 it's the long form, otherwise - * the ber element has the unsupported indefinite-length format. - * Lengths that do not fit in a ber_len_t are not accepted. + * Next, read the length. The first byte contains the length of + * the length. If bit 8 is set, the length is the long form, + * otherwise it's the short form. We don't allow a length that's + * greater than what we can hold in a ber_len_t. */ if ( ber_read( ber, (char *) &lc, 1 ) != 1 ) { return LBER_DEFAULT; } - len = lc; if ( lc & 0x80U ) { noctets = (lc & 0x7fU); - if ( noctets - 1U > sizeof(ber_len_t) - 1U ) { - /* Indefinite-length or too long length */ + if ( noctets > sizeof(ber_len_t) ) { return LBER_DEFAULT; } @@ -183,17 +180,17 @@ ber_skip_tag( BerElement *ber, ber_len_t return LBER_DEFAULT; } - len = netlen[0]; - for( i = 1; i < noctets; i++ ) { - len <<= 8; - len |= netlen[i]; + for( i = 0; i < noctets; i++ ) { + *len <<= 8; + *len |= netlen[i]; } + } else { + *len = lc; } - *lenp = len; /* BER element should have enough data left */ - if( len > (ber_len_t) ber_pvt_ber_remaining( ber ) ) { + if( *len > (ber_len_t) ber_pvt_ber_remaining( ber ) ) { return LBER_DEFAULT; } ber->ber_tag = *(unsigned char *)ber->ber_ptr; @@ -223,40 +220,41 @@ ber_peek_tag( return tag; } -ber_tag_t -ber_get_int( +static ber_len_t +ber_getnint( BerElement *ber, - ber_int_t *num ) + ber_int_t *num, + ber_len_t len ) { - ber_tag_t tag; - ber_len_t len; unsigned char buf[sizeof(ber_int_t)]; + assert( ber != NULL ); assert( num != NULL ); + assert( LBER_VALID( ber ) ); - if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) { - return LBER_DEFAULT; - } + /* + * The tag and length have already been stripped off. We should + * be sitting right before len bytes of 2's complement integer, + * ready to be read straight into an int. We may have to sign + * extend after we read it in. + */ if ( len > sizeof(ber_int_t) ) { - return LBER_DEFAULT; + return -1; } /* read into the low-order bytes of our buffer */ if ( (ber_len_t) ber_read( ber, (char *) buf, len ) != len ) { - return LBER_DEFAULT; + return -1; } - /* parse two's complement integer */ if( len ) { + /* sign extend if necessary */ ber_len_t i; - ber_int_t netnum = buf[0] & 0xff; - - /* sign extend */ - netnum -= (netnum & 0x80) << 1; + ber_int_t netnum = 0x80 & buf[0] ? -1 : 0; /* shift in the bytes */ - for( i = 1; i < len; i++ ) { + for( i=0 ; iber_tag = *(unsigned char *)ber->ber_ptr; + return len; +} + +ber_tag_t +ber_get_int( + BerElement *ber, + ber_int_t *num ) +{ + ber_tag_t tag; + ber_len_t len; + + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) { + return LBER_DEFAULT; + } + + if ( ber_getnint( ber, num, len ) != len ) { + return LBER_DEFAULT; + } + return tag; } @@ -288,6 +307,9 @@ ber_get_stringb( ber_len_t datalen; ber_tag_t tag; + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) { return LBER_DEFAULT; } @@ -385,7 +407,7 @@ ber_get_stringbvl( bgbvr *b, ber_len_t * case BvOff: *b->res.ba = ber_memalloc_x( (n+1) * b->siz, b->ber->ber_memctx ); if ( *b->res.ba == NULL ) return LBER_DEFAULT; - ((struct berval *)((char *)(*b->res.ba) + n*b->siz + + ((struct berval *)((long)(*b->res.ba) + n*b->siz + b->off))->bv_val = NULL; break; } @@ -411,14 +433,14 @@ ber_get_stringbvl( bgbvr *b, ber_len_t * case BvVec: bvp = ber_memalloc_x( sizeof( struct berval ), b->ber->ber_memctx); if ( !bvp ) { - ber_memfree_x( bv.bv_val, b->ber->ber_memctx ); + LBER_FREE(bv.bv_val); goto nomem; } (*b->res.bv)[n] = bvp; *bvp = bv; break; case BvOff: - *(BerVarray)((char *)(*b->res.ba)+n*b->siz+b->off) = bv; + *(BerVarray)((long)(*b->res.ba)+n*b->siz+b->off) = bv; break; } } @@ -429,21 +451,21 @@ nomem: for (--n; n>=0; n--) { switch(b->choice) { case ChArray: - ber_memfree_x((*b->res.c)[n], b->ber->ber_memctx); + LBER_FREE((*b->res.c)[n]); break; case BvArray: - ber_memfree_x((*b->res.ba)[n].bv_val, b->ber->ber_memctx); + LBER_FREE((*b->res.ba)[n].bv_val); break; case BvVec: - ber_memfree_x((*b->res.bv)[n]->bv_val, b->ber->ber_memctx); - ber_memfree_x((*b->res.bv)[n], b->ber->ber_memctx); + LBER_FREE((*b->res.bv)[n]->bv_val); + LBER_FREE((*b->res.bv)[n]); break; default: break; } } } - ber_memfree_x(*b->res.c, b->ber->ber_memctx); + LBER_FREE(*b->res.c); *b->res.c = NULL; return LBER_DEFAULT; } @@ -453,12 +475,18 @@ ber_get_stringbv( BerElement *ber, struc { ber_tag_t tag; + assert( ber != NULL ); assert( bv != NULL ); - tag = ber_skip_tag( ber, &bv->bv_len ); - if ( tag == LBER_DEFAULT ) { + assert( LBER_VALID( ber ) ); + + if ( (tag = ber_skip_tag( ber, &bv->bv_len )) == LBER_DEFAULT ) { bv->bv_val = NULL; - return tag; + return LBER_DEFAULT; + } + + if ( (ber_len_t) ber_pvt_ber_remaining( ber ) < bv->bv_len ) { + return LBER_DEFAULT; } if ( option & LBER_BV_ALLOC ) { @@ -471,7 +499,7 @@ ber_get_stringbv( BerElement *ber, struc if ( bv->bv_len > 0 && (ber_len_t) ber_read( ber, bv->bv_val, bv->bv_len ) != bv->bv_len ) { - ber_memfree_x( bv->bv_val, ber->ber_memctx ); + LBER_FREE( bv->bv_val ); bv->bv_val = NULL; return LBER_DEFAULT; } @@ -491,11 +519,23 @@ ber_get_stringbv_null( BerElement *ber, { ber_tag_t tag; + assert( ber != NULL ); assert( bv != NULL ); - tag = ber_skip_tag( ber, &bv->bv_len ); - if ( tag == LBER_DEFAULT || bv->bv_len == 0 ) { + assert( LBER_VALID( ber ) ); + + if ( (tag = ber_skip_tag( ber, &bv->bv_len )) == LBER_DEFAULT ) { bv->bv_val = NULL; + return LBER_DEFAULT; + } + + if ( (ber_len_t) ber_pvt_ber_remaining( ber ) < bv->bv_len ) { + return LBER_DEFAULT; + } + + if ( bv->bv_len == 0 ) { + bv->bv_val = NULL; + ber->ber_tag = *(unsigned char *)ber->ber_ptr; return tag; } @@ -509,7 +549,7 @@ ber_get_stringbv_null( BerElement *ber, if ( bv->bv_len > 0 && (ber_len_t) ber_read( ber, bv->bv_val, bv->bv_len ) != bv->bv_len ) { - ber_memfree_x( bv->bv_val, ber->ber_memctx ); + LBER_FREE( bv->bv_val ); bv->bv_val = NULL; return LBER_DEFAULT; } @@ -568,7 +608,7 @@ ber_get_stringal( BerElement *ber, struc tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC ); if ( tag == LBER_DEFAULT ) { - ber_memfree_x( *bv, ber->ber_memctx ); + LBER_FREE( *bv ); *bv = NULL; } return tag; @@ -584,30 +624,31 @@ ber_get_bitstringa( ber_tag_t tag; unsigned char unusedbits; + assert( ber != NULL ); assert( buf != NULL ); assert( blen != NULL ); - if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) { - goto fail; - } + assert( LBER_VALID( ber ) ); - if ( --datalen > (ber_len_t)-1 / 8 ) { - goto fail; - } - if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 ) { - goto fail; - } - if ( unusedbits > 7 ) { - goto fail; + if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) { + *buf = NULL; + return LBER_DEFAULT; } + --datalen; *buf = (char *) ber_memalloc_x( datalen, ber->ber_memctx ); if ( *buf == NULL ) { return LBER_DEFAULT; } + if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 ) { + LBER_FREE( buf ); + *buf = NULL; + return LBER_DEFAULT; + } + if ( (ber_len_t) ber_read( ber, *buf, datalen ) != datalen ) { - ber_memfree_x( buf, ber->ber_memctx ); + LBER_FREE( buf ); *buf = NULL; return LBER_DEFAULT; } @@ -615,19 +656,27 @@ ber_get_bitstringa( *blen = datalen * 8 - unusedbits; return tag; - - fail: - *buf = NULL; - return LBER_DEFAULT; } ber_tag_t ber_get_null( BerElement *ber ) { ber_len_t len; - ber_tag_t tag = ber_skip_tag( ber, &len ); + ber_tag_t tag; + + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) { + return LBER_DEFAULT; + } + + if ( len != 0 ) { + return LBER_DEFAULT; + } + ber->ber_tag = *(unsigned char *)ber->ber_ptr; - return( len == 0 ? tag : LBER_DEFAULT ); + return( tag ); } ber_tag_t @@ -635,7 +684,18 @@ ber_get_boolean( BerElement *ber, ber_int_t *boolval ) { - return ber_get_int( ber, boolval ); + ber_int_t longbool; + ber_tag_t rc; + + assert( ber != NULL ); + assert( boolval != NULL ); + + assert( LBER_VALID( ber ) ); + + rc = ber_get_int( ber, &longbool ); + *boolval = longbool; + + return rc; } ber_tag_t @@ -644,6 +704,8 @@ ber_first_element( ber_len_t *len, char **last ) { + assert( ber != NULL ); + assert( len != NULL ); assert( last != NULL ); /* skip the sequence header, use the len to mark where to stop */ @@ -651,10 +713,11 @@ ber_first_element( *last = NULL; return LBER_DEFAULT; } + ber->ber_tag = *(unsigned char *)ber->ber_ptr; *last = ber->ber_ptr + *len; - if ( *len == 0 ) { + if ( *last == ber->ber_ptr ) { return LBER_DEFAULT; } @@ -668,7 +731,9 @@ ber_next_element( LDAP_CONST char *last ) { assert( ber != NULL ); + assert( len != NULL ); assert( last != NULL ); + assert( LBER_VALID( ber ) ); if ( ber->ber_ptr >= last ) { @@ -686,8 +751,8 @@ ber_scanf ( BerElement *ber, { va_list ap; LDAP_CONST char *fmt_reset; - char *s, **ss, ***sss; - struct berval *bval, **bvp, ***bvpp; + char *s, **ss; + struct berval **bvp, *bval; ber_int_t *i; ber_len_t *l; ber_tag_t *t; @@ -698,15 +763,14 @@ ber_scanf ( BerElement *ber, assert( ber != NULL ); assert( fmt != NULL ); + assert( LBER_VALID( ber ) ); fmt_reset = fmt; - if ( ber->ber_debug & (LDAP_DEBUG_TRACE|LDAP_DEBUG_BER)) { - ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, - "ber_scanf fmt (%s) ber:\n", fmt ); - ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 ); - } + ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, + "ber_scanf fmt (%s) ber:\n", fmt ); + ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 ); for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) { /* When this is modified, remember to update @@ -745,7 +809,7 @@ ber_scanf ( BerElement *ber, break; case 'e': /* enumerated */ - case 'i': /* integer */ + case 'i': /* int */ i = va_arg( ap, ber_int_t * ); rc = ber_get_int( ber, i ); break; @@ -846,13 +910,9 @@ ber_scanf ( BerElement *ber, case '{': /* begin sequence */ case '[': /* begin set */ - switch ( fmt[1] ) { - case 'v': case 'V': case 'W': case 'M': - break; - default: + if ( *(fmt + 1) != 'v' && *(fmt + 1) != 'V' + && *(fmt + 1) != 'W' && *(fmt + 1) != 'M' ) rc = ber_skip_tag( ber, &len ); - break; - } break; case '}': /* end sequence */ @@ -870,7 +930,6 @@ ber_scanf ( BerElement *ber, } va_end( ap ); - if ( rc == LBER_DEFAULT ) { /* * Error. Reclaim malloced memory that was given to the caller. @@ -893,48 +952,42 @@ ber_scanf ( BerElement *ber, case 'a': /* octet string - allocate storage as needed */ case 'A': ss = va_arg( ap, char ** ); - ber_memfree_x( *ss, ber->ber_memctx ); - *ss = NULL; + if ( *ss ) { + LBER_FREE( *ss ); + *ss = NULL; + } break; case 'b': /* boolean */ case 'e': /* enumerated */ - case 'i': /* integer */ - (void) va_arg( ap, ber_int_t * ); + case 'i': /* int */ + (void) va_arg( ap, int * ); break; case 'l': /* length of next item */ - *(va_arg( ap, ber_len_t * )) = 0; - break; - - case 'm': /* berval in-place */ - bval = va_arg( ap, struct berval * ); - BER_BVZERO( bval ); - break; - - case 'M': /* BVoff array in-place */ - bvp = va_arg( ap, struct berval ** ); - ber_memfree_x( bvp, ber->ber_memctx ); - *bvp = NULL; - *(va_arg( ap, ber_len_t * )) = 0; - (void) va_arg( ap, ber_len_t ); + (void) va_arg( ap, ber_len_t * ); break; case 'o': /* octet string in a supplied berval */ bval = va_arg( ap, struct berval * ); - ber_memfree_x( bval->bv_val, ber->ber_memctx ); - BER_BVZERO( bval ); + if ( bval->bv_val != NULL ) { + LBER_FREE( bval->bv_val ); + bval->bv_val = NULL; + } + bval->bv_len = 0; break; case 'O': /* octet string - allocate & include length */ bvp = va_arg( ap, struct berval ** ); - ber_bvfree_x( *bvp, ber->ber_memctx ); - *bvp = NULL; + if ( *bvp ) { + ber_bvfree( *bvp ); + *bvp = NULL; + } break; case 's': /* octet string - in a buffer */ (void) va_arg( ap, char * ); - *(va_arg( ap, ber_len_t * )) = 0; + (void) va_arg( ap, ber_len_t * ); break; case 't': /* tag of next item */ @@ -944,30 +997,19 @@ ber_scanf ( BerElement *ber, case 'B': /* bit string - allocate storage as needed */ ss = va_arg( ap, char ** ); - ber_memfree_x( *ss, ber->ber_memctx ); - *ss = NULL; + if ( *ss ) { + LBER_FREE( *ss ); + *ss = NULL; + } *(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */ break; + case 'm': /* berval in-place */ + case 'M': /* BVoff array in-place */ + case 'n': /* null */ case 'v': /* sequence of strings */ - sss = va_arg( ap, char *** ); - ber_memvfree_x( (void **) *sss, ber->ber_memctx ); - *sss = NULL; - break; - case 'V': /* sequence of strings + lengths */ - bvpp = va_arg( ap, struct berval *** ); - ber_bvecfree_x( *bvpp, ber->ber_memctx ); - *bvpp = NULL; - break; - case 'W': /* BerVarray */ - bvp = va_arg( ap, struct berval ** ); - ber_bvarray_free_x( *bvp, ber->ber_memctx ); - *bvp = NULL; - break; - - case 'n': /* null */ case 'x': /* skip the next element - whatever it is */ case '{': /* begin sequence */ case '[': /* begin set */