X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=libraries%2Flibldap%2Fgetdn.c;h=0dee28d71f9134f3962030ac9e8413ee99dc2b39;hb=df312502ac486d78fb67ad53a02742f18ea6fcec;hp=d48add09f7ff00a161fd574f03790157d7f32cbd;hpb=fdb62b5650b895787c8a558140ccd383d38a2ded;p=openldap diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index d48add09f7..0dee28d71f 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -1,13 +1,19 @@ /* $OpenLDAP$ */ -/* - * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file - */ -/* Portions - * Copyright (c) 1994 Regents of the University of Michigan. - * All rights reserved. +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2004 The OpenLDAP Foundation. + * All rights reserved. * - * getdn.c + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* Portions Copyright (c) 1994 Regents of the University of Michigan. + * All rights reserved. */ #include "portable.h" @@ -25,19 +31,19 @@ /* extension to UFN that turns trailing "dc=value" rdns in DNS style, * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */ #define DC_IN_UFN -/* #define PRETTY_ESCAPE */ +#define PRETTY_ESCAPE /* parsing/printing routines */ -static int str2strval( const char *str, struct berval *val, - const char **next, unsigned flags, unsigned *retFlags ); +static int str2strval( const char *str, ber_len_t stoplen, struct berval *val, + const char **next, unsigned flags, int *retFlags, void *ctx ); static int DCE2strval( const char *str, struct berval *val, - const char **next, unsigned flags ); + const char **next, unsigned flags, void *ctx ); static int IA52strval( const char *str, struct berval *val, - const char **next, unsigned flags ); + const char **next, unsigned flags, void *ctx ); static int quotedIA52strval( const char *str, struct berval *val, - const char **next, unsigned flags ); + const char **next, unsigned flags, void *ctx ); static int hexstr2binval( const char *str, struct berval *val, - const char **next, unsigned flags ); + const char **next, unsigned flags, void *ctx ); static int hexstr2bin( const char *str, char *c ); static int byte2hexpair( const char *val, char *pair ); static int binval2hexstr( struct berval *val, char *str ); @@ -57,23 +63,23 @@ static int strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len ); static int strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ); -static int dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN ); +static int dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN ); /* AVA helpers */ static LDAPAVA * ldapava_new( - const struct berval *attr, const struct berval *val, unsigned flags ); + const struct berval *attr, const struct berval *val, unsigned flags, void *ctx ); /* Higher level helpers */ -static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len, +static int rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len, int ( *s2l )( struct berval *, unsigned, ber_len_t * ) ); -static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, +static int rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * )); -static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ); -static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len ); -static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ); -static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first ); -static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ); -static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ); +static int rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ); +static int rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len ); +static int rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ); +static int rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flag, ber_len_t *len, int first ); +static int rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ); +static int rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first ); /* * RFC 1823 ldap_get_dn @@ -84,12 +90,15 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry ) char *dn; BerElement tmp; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_get_dn\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 ); +#endif - if ( entry == NULL ) { - ld->ld_errno = LDAP_PARAM_ERROR; - return( NULL ); - } + assert( ld != NULL ); + assert( LDAP_VALID(ld) ); + assert( entry != NULL ); tmp = *entry->lm_ber; /* struct copy */ if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) { @@ -100,6 +109,57 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry ) return( dn ); } +int +ldap_get_dn_ber( LDAP *ld, LDAPMessage *entry, BerElement **berout, + BerValue *dn ) +{ + BerElement tmp, *ber; + ber_len_t len = 0; + int rc = LDAP_SUCCESS; + +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_get_dn_ber\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_get_dn_ber\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID(ld) ); + assert( entry != NULL ); + assert( dn != NULL ); + + dn->bv_val = NULL; + dn->bv_len = 0; + + if ( berout ) { + *berout = NULL; + ber = ldap_alloc_ber_with_options( ld ); + if( ber == NULL ) { + return LDAP_NO_MEMORY; + } + *berout = ber; + } else { + ber = &tmp; + } + + *ber = *entry->lm_ber; /* struct copy */ + if ( ber_scanf( ber, "{ml{" /*}*/, dn, &len ) == LBER_ERROR ) { + rc = ld->ld_errno = LDAP_DECODING_ERROR; + } + if ( rc == LDAP_SUCCESS ) { + /* set the length to avoid overrun */ + rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len ); + if( rc != LBER_OPT_SUCCESS ) { + rc = ld->ld_errno = LDAP_LOCAL_ERROR; + } + } + if ( rc != LDAP_SUCCESS && berout ) { + ber_free( ber, 0 ); + *berout = NULL; + } + return rc; +} + /* * RFC 1823 ldap_dn2ufn */ @@ -108,10 +168,14 @@ ldap_dn2ufn( LDAP_CONST char *dn ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_dn2ufn\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, - &out, LDAP_DN_FORMAT_UFN ); + &out, LDAP_DN_FORMAT_UFN ); return( out ); } @@ -122,12 +186,16 @@ ldap_dn2ufn( LDAP_CONST char *dn ) char ** ldap_explode_dn( LDAP_CONST char *dn, int notypes ) { - LDAPDN *tmpDN; + LDAPDN tmpDN; char **values = NULL; int iRDN; unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_explode_dn\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 ); +#endif if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) { @@ -142,7 +210,7 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes ) return values; } - for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ ); + for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ); values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) ); if ( values == NULL ) { @@ -150,8 +218,8 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes ) return NULL; } - for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ ) { - ldap_rdn2str( tmpDN[ 0 ][ iRDN ], &values[ iRDN ], flag ); + for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) { + ldap_rdn2str( tmpDN[ iRDN ], &values[ iRDN ], flag ); } ldap_dnfree( tmpDN ); values[ iRDN ] = NULL; @@ -162,36 +230,40 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes ) char ** ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) { - LDAPRDN *tmpRDN; + LDAPRDN tmpRDN; char **values = NULL; const char *p; int iAVA; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_explode_rdn\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 ); +#endif /* * we only parse the first rdn * FIXME: we prefer efficiency over checking if the _ENTIRE_ * dn can be parsed */ - if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP ) + if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) { return( NULL ); } - for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) ; + for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ; values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) ); if ( values == NULL ) { ldap_rdnfree( tmpRDN ); return( NULL ); } - for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) { + for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) { ber_len_t l = 0, vl, al = 0; char *str; - LDAPAVA *ava = tmpRDN[ 0 ][ iAVA ]; + LDAPAVA *ava = tmpRDN[ iAVA ]; - if ( ava->la_flags == LDAP_AVA_BINARY ) { + if ( ava->la_flags & LDAP_AVA_BINARY ) { vl = 1 + 2 * ava->la_value.bv_len; } else { @@ -215,7 +287,7 @@ ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) str = LDAP_MALLOC( l + 1 ); } - if ( ava->la_flags == LDAP_AVA_BINARY ) { + if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ al++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) { goto error_return; @@ -248,7 +320,11 @@ ldap_dn2dcedn( LDAP_CONST char *dn ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_dn2dcedn\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE ); @@ -261,7 +337,11 @@ ldap_dcedn2dn( LDAP_CONST char *dce ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_dcedn2dn\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 ); @@ -273,7 +353,11 @@ ldap_dn2ad_canonical( LDAP_CONST char *dn ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_dn2ad_canonical\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_AD_CANONICAL ); @@ -299,12 +383,17 @@ ldap_dn2ad_canonical( LDAP_CONST char *dn ) * LDAP_DN_FORMAT_AD_CANONICAL (?) */ int -ldap_dn_normalize( const char *dnin, unsigned fin, char **dnout, unsigned fout ) +ldap_dn_normalize( LDAP_CONST char *dnin, + unsigned fin, char **dnout, unsigned fout ) { int rc; - LDAPDN *tmpDN = NULL; + LDAPDN tmpDN = NULL; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ENTRY, "ldap_dn_normalize\n", 0, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 ); +#endif assert( dnout ); @@ -383,10 +472,12 @@ ldap_dn_normalize( const char *dnin, unsigned fin, char **dnout, unsigned fout ) #define LDAP_DN_NE(c) \ ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \ || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' ) +#define LDAP_DN_MAYESCAPE(c) \ + ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \ + || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) ) #define LDAP_DN_NEEDESCAPE(c) \ ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) ) -#define LDAP_DN_NEEDESCAPE_LEAD(c) \ - ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) ) +#define LDAP_DN_NEEDESCAPE_LEAD(c) LDAP_DN_MAYESCAPE(c) #define LDAP_DN_NEEDESCAPE_TRAIL(c) \ ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) ) #define LDAP_DN_WILLESCAPE_CHAR(c) \ @@ -457,13 +548,13 @@ ldap_dn_normalize( const char *dnin, unsigned fin, char **dnout, unsigned fout ) #define LDAP_DC_ATTR "dc" #define LDAP_DC_ATTRU "DC" #define LDAP_DN_IS_RDN_DC( r ) \ - ( (r) && (r)[0][0] && !(r)[0][1] \ - && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \ - && ((r)[0][0]->la_attr.bv_len == 2) \ - && (((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \ - || ((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \ - && (((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \ - || ((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1]))) + ( (r) && (r)[0] && !(r)[1] \ + && ((r)[0]->la_flags & LDAP_AVA_STRING) \ + && ((r)[0]->la_attr.bv_len == 2) \ + && (((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \ + || ((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \ + && (((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \ + || ((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1]))) /* Composite rules */ #define LDAP_DN_ALLOW_ONE_SPACE(f) \ @@ -492,35 +583,32 @@ ldap_dn_normalize( const char *dnin, unsigned fin, char **dnout, unsigned fout ) */ LDAPAVA * ldapava_new( const struct berval *attr, const struct berval *val, - unsigned flags ) + unsigned flags, void *ctx ) { - LDAPAVA *ava; + LDAPAVA *ava; assert( attr ); assert( val ); - ava = LDAP_MALLOC( sizeof( LDAPAVA ) + attr->bv_len + 1 ); - - /* should we test it? */ - if ( ava == NULL ) { - return( NULL ); - } + ava = LDAP_MALLOCX( sizeof( LDAPAVA ) + attr->bv_len + 1, ctx ); - ava->la_attr.bv_len = attr->bv_len; - ava->la_attr.bv_val = (char *)(ava+1); - AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len ); - ava->la_attr.bv_val[attr->bv_len] = '\0'; + if ( ava ) { + ava->la_attr.bv_len = attr->bv_len; + ava->la_attr.bv_val = (char *)(ava+1); + AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len ); + ava->la_attr.bv_val[attr->bv_len] = '\0'; - ava->la_value = *val; - ava->la_flags = flags; + ava->la_value = *val; + ava->la_flags = flags | LDAP_AVA_FREE_VALUE; - ava->la_private = NULL; + ava->la_private = NULL; + } return( ava ); } void -ldap_avafree( LDAPAVA *ava ) +ldapava_free( LDAPAVA *ava, void *ctx ) { assert( ava ); @@ -531,17 +619,20 @@ ldap_avafree( LDAPAVA *ava ) assert( ava->la_private == NULL ); #endif -#if 0 - /* la_attr is now contiguous with ava, not freed separately */ - free( ava->la_attr.bv_val ); -#endif - free( ava->la_value.bv_val ); + if (ava->la_flags & LDAP_AVA_FREE_VALUE) + LDAP_FREEX( ava->la_value.bv_val, ctx ); - LDAP_FREE( ava ); + LDAP_FREEX( ava, ctx ); +} + +void +ldap_rdnfree( LDAPRDN rdn ) +{ + ldap_rdnfree_x( rdn, NULL ); } void -ldap_rdnfree( LDAPRDN *rdn ) +ldap_rdnfree_x( LDAPRDN rdn, void *ctx ) { int iAVA; @@ -549,15 +640,21 @@ ldap_rdnfree( LDAPRDN *rdn ) return; } - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - ldap_avafree( rdn[ 0 ][ iAVA ] ); + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + ldapava_free( rdn[ iAVA ], ctx ); } - LDAP_FREE( rdn ); + LDAP_FREEX( rdn, ctx ); } void -ldap_dnfree( LDAPDN *dn ) +ldap_dnfree( LDAPDN dn ) +{ + ldap_dnfree_x( dn, NULL ); +} + +void +ldap_dnfree_x( LDAPDN dn, void *ctx ) { int iRDN; @@ -565,11 +662,11 @@ ldap_dnfree( LDAPDN *dn ) return; } - for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { - ldap_rdnfree( dn[ 0 ][ iRDN ] ); + for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) { + ldap_rdnfree_x( dn[ iRDN ], ctx ); } - LDAP_FREE( dn ); + LDAP_FREEX( dn, ctx ); } /* @@ -586,22 +683,56 @@ ldap_dnfree( LDAPDN *dn ) * and readable as soon as it works as expected. */ -#define TMP_SLOTS 1024 +/* + * Default sizes of AVA and RDN static working arrays; if required + * the are dynamically resized. The values can be tuned in case + * of special requirements (e.g. very deep DN trees or high number + * of AVAs per RDN). + */ +#define TMP_AVA_SLOTS 8 +#define TMP_RDN_SLOTS 32 int -ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) +ldap_str2dn( LDAP_CONST char *str, LDAPDN *dn, unsigned flags ) +{ + struct berval bv; + + assert( str ); + + bv.bv_len = strlen( str ); + bv.bv_val = (char *) str; + + return ldap_bv2dn_x( &bv, dn, flags, NULL ); +} + +int +ldap_bv2dn( struct berval *bv, LDAPDN *dn, unsigned flags ) +{ + return ldap_bv2dn_x( bv, dn, flags, NULL ); +} + +int +ldap_bv2dn_x( struct berval *bv, LDAPDN *dn, unsigned flags, void *ctx ) { const char *p; - int rc = LDAP_INVALID_DN_SYNTAX; + int rc = LDAP_DECODING_ERROR; int nrdns = 0; - LDAPDN *newDN = NULL; - LDAPRDN *newRDN = NULL, *tmpDN[TMP_SLOTS]; + LDAPDN newDN = NULL; + LDAPRDN newRDN = NULL, tmpDN_[TMP_RDN_SLOTS], *tmpDN = tmpDN_; + int num_slots = TMP_RDN_SLOTS; + char *str = bv->bv_val; + char *end = str + bv->bv_len; - assert( str ); + assert( bv ); + assert( bv->bv_val ); assert( dn ); - Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" ); +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ARGS, "ldap_bv2dn(%s,%u)\n%s", str, flags, "" ); +#else + Debug( LDAP_DEBUG_TRACE, "=> ldap_bv2dn(%s,%u)\n%s", str, flags, "" ); +#endif *dn = NULL; @@ -615,14 +746,20 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) /* unsupported in str2dn */ case LDAP_DN_FORMAT_UFN: case LDAP_DN_FORMAT_AD_CANONICAL: - return( LDAP_INVALID_DN_SYNTAX ); + return LDAP_PARAM_ERROR; + case LDAP_DN_FORMAT_LBER: default: - return( LDAP_OTHER ); + return LDAP_PARAM_ERROR; } - if ( str[ 0 ] == '\0' ) { - return( LDAP_SUCCESS ); + if ( bv->bv_len == 0 ) { + return LDAP_SUCCESS; + } + + if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) { + /* value must have embedded NULs */ + return LDAP_DECODING_ERROR; } p = str; @@ -636,7 +773,12 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) goto parsing_error; } p++; - + + /* + * actually we do not want to accept by default the DCE form, + * we do not want to auto-detect it + */ +#if 0 } else if ( LDAP_DN_LDAP( flags ) ) { /* * if dn starts with '/' let's make it a DCE dn @@ -645,12 +787,16 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) flags |= LDAP_DN_FORMAT_DCE; p++; } +#endif } - for ( ; p[ 0 ]; p++ ) { + for ( ; p < end; p++ ) { int err; + struct berval tmpbv; + tmpbv.bv_len = bv->bv_len - ( p - str ); + tmpbv.bv_val = (char *)p; - err = ldap_str2rdn( p, &newRDN, &p, flags ); + err = ldap_bv2rdn_x( &tmpbv, &newRDN, (char **) &p, flags,ctx); if ( err != LDAP_SUCCESS ) { goto parsing_error; } @@ -658,11 +804,11 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) /* * We expect a rdn separator */ - if ( p[ 0 ] ) { + if ( p < end && p[ 0 ] ) { switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) { - rc = LDAP_OTHER; + rc = LDAP_DECODING_ERROR; goto parsing_error; } break; @@ -670,14 +816,14 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV2: if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) { - rc = LDAP_OTHER; + rc = LDAP_DECODING_ERROR; goto parsing_error; } break; case LDAP_DN_FORMAT_DCE: if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) { - rc = LDAP_OTHER; + rc = LDAP_DECODING_ERROR; goto parsing_error; } break; @@ -688,31 +834,52 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) tmpDN[nrdns++] = newRDN; newRDN = NULL; - assert (nrdns < TMP_SLOTS); + /* + * make the static RDN array dynamically rescalable + */ + if ( nrdns == num_slots ) { + LDAPRDN *tmp; + + if ( tmpDN == tmpDN_ ) { + tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPRDN * ), ctx ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) ); + + } else { + tmp = LDAP_REALLOCX( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ), ctx ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + } + + tmpDN = tmp; + num_slots *= 2; + } - if ( p[ 0 ] == '\0' ) { + if ( p >= end || p[ 0 ] == '\0' ) { /* * the DN is over, phew */ - newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) + - sizeof(LDAPRDN *) * (nrdns+1)); + newDN = (LDAPDN)LDAP_MALLOCX( sizeof(LDAPRDN *) * (nrdns+1), ctx ); if ( newDN == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } else { int i; - newDN[0] = (LDAPRDN **)(newDN+1); - if ( LDAP_DN_DCE( flags ) ) { /* add in reversed order */ for ( i=0; i=0; nrdns-- ) - ldap_rdnfree( tmpDN[nrdns] ); + for ( nrdns-- ;nrdns >= 0; nrdns-- ) { + ldap_rdnfree_x( tmpDN[nrdns], ctx ); + } return_result:; - Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc ); + if ( tmpDN != tmpDN_ ) { + LDAP_FREEX( tmpDN, ctx ); + } + +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, "<= ldap_bv2dn(%s,%u)=%d\n", + str, flags, rc ); +#else + Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s,%u)=%d\n", str, flags, rc ); +#endif *dn = newDN; return( rc ); @@ -744,26 +921,57 @@ return_result:; * corresponds to the rdn separator or to '\0' in case the string is over. */ int -ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) +ldap_str2rdn( LDAP_CONST char *str, LDAPRDN *rdn, + char **n_in, unsigned flags ) { + struct berval bv; + + assert( str ); + assert( str[ 0 ] != '\0' ); /* FIXME: is this required? */ + + bv.bv_len = strlen( str ); + bv.bv_val = (char *) str; + + return ldap_bv2rdn_x( &bv, rdn, n_in, flags, NULL ); +} + +int +ldap_bv2rdn( struct berval *bv, LDAPRDN *rdn, + char **n_in, unsigned flags ) +{ + return ldap_bv2rdn_x( bv, rdn, n_in, flags, NULL ); +} + +int +ldap_bv2rdn_x( struct berval *bv, LDAPRDN *rdn, + char **n_in, unsigned flags, void *ctx ) +{ + const char **n = (const char **) n_in; const char *p; int navas = 0; int state = B4AVA; - int rc = LDAP_INVALID_DN_SYNTAX; + int rc = LDAP_DECODING_ERROR; int attrTypeEncoding = LDAP_AVA_STRING, attrValueEncoding = LDAP_AVA_STRING; struct berval attrType = { 0, NULL }; struct berval attrValue = { 0, NULL }; - LDAPRDN *newRDN = NULL; - LDAPAVA *tmpRDN[TMP_SLOTS]; + LDAPRDN newRDN = NULL; + LDAPAVA *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_; + int num_slots = TMP_AVA_SLOTS; + + char *str; + ber_len_t stoplen; - assert( str ); + assert( bv ); + assert( bv->bv_len ); + assert( bv->bv_val ); assert( rdn || flags & LDAP_DN_SKIP ); assert( n ); - Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" ); + str = bv->bv_val; + stoplen = bv->bv_len; if ( rdn ) { *rdn = NULL; @@ -780,14 +988,21 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) /* unsupported in str2dn */ case LDAP_DN_FORMAT_UFN: case LDAP_DN_FORMAT_AD_CANONICAL: - return( LDAP_INVALID_DN_SYNTAX ); + return LDAP_PARAM_ERROR; + case LDAP_DN_FORMAT_LBER: default: - return( LDAP_OTHER ); + return LDAP_PARAM_ERROR; } - if ( str[ 0 ] == '\0' ) { - return( LDAP_SUCCESS ); + if ( bv->bv_len == 0 ) { + return LDAP_SUCCESS; + + } + + if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) { + /* value must have embedded NULs */ + return LDAP_DECODING_ERROR; } p = str; @@ -1036,11 +1251,16 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) * here STRING means RFC 2253 string * FIXME: what about DCE strings? */ - state = B4STRINGVALUE; + if ( !p[ 0 ] ) { + /* empty value */ + state = GOTAVA; + } else { + state = B4STRINGVALUE; + } break; case B4BINARYVALUE: - if ( hexstr2binval( p, &attrValue, &p, flags ) ) { + if ( hexstr2binval( p, &attrValue, &p, flags, ctx ) ) { goto parsing_error; } @@ -1051,14 +1271,15 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV3: - if ( str2strval( p, &attrValue, &p, flags, - &attrValueEncoding ) ) { + if ( str2strval( p, stoplen - ( p - str ), + &attrValue, &p, flags, + &attrValueEncoding, ctx ) ) { goto parsing_error; } break; case LDAP_DN_FORMAT_DCE: - if ( DCE2strval( p, &attrValue, &p, flags ) ) { + if ( DCE2strval( p, &attrValue, &p, flags, ctx ) ) { goto parsing_error; } break; @@ -1071,7 +1292,7 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) break; case B4IA5VALUE: - if ( IA52strval( p, &attrValue, &p, flags ) ) { + if ( IA52strval( p, &attrValue, &p, flags, ctx ) ) { goto parsing_error; } @@ -1082,7 +1303,7 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) /* lead quote already stripped */ if ( quotedIA52strval( p, &attrValue, - &p, flags ) ) { + &p, flags, ctx ) ) { goto parsing_error; } @@ -1099,14 +1320,41 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) * we accept empty values */ ava = ldapava_new( &attrType, &attrValue, - attrValueEncoding ); + attrValueEncoding, ctx ); if ( ava == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } tmpRDN[navas++] = ava; - assert(navas < TMP_SLOTS); + attrValue.bv_val = NULL; + attrValue.bv_len = 0; + + /* + * prepare room for new AVAs if needed + */ + if (navas == num_slots) { + LDAPAVA **tmp; + + if ( tmpRDN == tmpRDN_ ) { + tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPAVA * ), ctx ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) ); + + } else { + tmp = LDAP_REALLOCX( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ), ctx ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + } + + tmpRDN = tmp; + num_slots *= 2; + } } /* @@ -1136,19 +1384,14 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) */ *n = p; if ( !( flags & LDAP_DN_SKIP ) ) { - newRDN = (LDAPRDN *)LDAP_MALLOC( sizeof(LDAPRDN) - + sizeof(LDAPAVA *) * (navas+1) ); + newRDN = (LDAPRDN)LDAP_MALLOCX( + sizeof(LDAPAVA) * (navas+1), ctx ); if ( newRDN == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } else { - int i; - - newRDN[0] = (LDAPAVA**)(newRDN+1); - - for (i=0; i=0; navas-- ) - ldap_avafree( tmpRDN[navas] ); + for ( navas-- ; navas >= 0; navas-- ) { + ldapava_free( tmpRDN[navas], ctx ); + } return_result:; - Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n", - p - str, str, rc ); + if ( tmpRDN != tmpRDN_ ) { + LDAP_FREEX( tmpRDN, ctx ); + } + if ( rdn ) { *rdn = newRDN; } @@ -1199,26 +1445,24 @@ return_result:; * '\' + HEXPAIR(p) -> unhex(p) */ static int -str2strval( const char *str, struct berval *val, const char **next, unsigned flags, unsigned *retFlags ) +str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, int *retFlags, void *ctx ) { - const char *p, *startPos, *endPos = NULL; - ber_len_t len, escapes, unescapes; + const char *p, *end, *startPos, *endPos = NULL; + ber_len_t len, escapes; assert( str ); assert( val ); assert( next ); *next = NULL; - - for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) { + end = str + stoplen; + for ( startPos = p = str, escapes = 0; p < end; p++ ) { if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) { p++; if ( p[ 0 ] == '\0' ) { return( 1 ); } - if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) - || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) - || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) { + if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) { escapes++; continue; } @@ -1245,14 +1489,18 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla return( 1 ); } /* - * FIXME: we allow escaping + * we do not allow escaping * of chars that don't need * to and do not belong to - * HEXDIGITS (we also allow - * single hexdigit; maybe we - * shouldn't). + * HEXDIGITS */ - unescapes++; + return( 1 ); + + } else if (!LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) { + if ( p[ 0 ] == '\0' ) { + return( 1 ); + } + *retFlags = LDAP_AVA_NONPRINTABLE; } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) { @@ -1295,22 +1543,26 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla /* * FIXME: test memory? */ - len = ( endPos ? endPos : p ) - startPos - escapes - unescapes; + len = ( endPos ? endPos : p ) - startPos - escapes; val->bv_len = len; - if ( escapes == 0 && unescapes == 0 ) { - val->bv_val = LDAP_STRNDUP( startPos, len ); + if ( escapes == 0 ) { + if ( *retFlags & LDAP_AVA_NONPRINTABLE ) { + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); + AC_MEMCPY( val->bv_val, startPos, len ); + val->bv_val[ len ] = '\0'; + } else { + val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); + } } else { ber_len_t s, d; - val->bv_val = LDAP_MALLOC( len + 1 ); + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); for ( s = 0, d = 0; d < len; ) { if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) { s++; - if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) ) - || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) ) - || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) { + if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) { val->bv_val[ d++ ] = startPos[ s++ ]; @@ -1322,12 +1574,8 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla s += 2; } else { - /* - * we allow escaping of chars - * that do not need to - */ - val->bv_val[ d++ ] = - startPos[ s++ ]; + /* we should never get here */ + assert( 0 ); } } else { @@ -1336,14 +1584,14 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla } val->bv_val[ d ] = '\0'; - assert( strlen( val->bv_val ) == len ); + assert( d == len ); } return( 0 ); } static int -DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags ) +DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len, escapes; @@ -1402,12 +1650,12 @@ DCE2strval( const char *str, struct berval *val, const char **next, unsigned fla len = ( endPos ? endPos : p ) - startPos - escapes; val->bv_len = len; if ( escapes == 0 ){ - val->bv_val = LDAP_STRNDUP( startPos, len ); + val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); } else { ber_len_t s, d; - val->bv_val = LDAP_MALLOC( len + 1 ); + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); for ( s = 0, d = 0; d < len; ) { /* * This point is reached only if escapes @@ -1428,7 +1676,7 @@ DCE2strval( const char *str, struct berval *val, const char **next, unsigned fla } static int -IA52strval( const char *str, struct berval *val, const char **next, unsigned flags ) +IA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len, escapes; @@ -1483,12 +1731,12 @@ IA52strval( const char *str, struct berval *val, const char **next, unsigned fla len = ( endPos ? endPos : p ) - startPos - escapes; val->bv_len = len; if ( escapes == 0 ) { - val->bv_val = LDAP_STRNDUP( startPos, len ); + val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); } else { ber_len_t s, d; - val->bv_val = LDAP_MALLOC( len + 1 ); + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); for ( s = 0, d = 0; d < len; ) { if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) { s++; @@ -1503,7 +1751,7 @@ IA52strval( const char *str, struct berval *val, const char **next, unsigned fla } static int -quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags ) +quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len; @@ -1570,15 +1818,15 @@ quotedIA52strval( const char *str, struct berval *val, const char **next, unsign } len = endPos - startPos - escapes; - assert( len >= 0 ); + assert( endPos >= startPos + escapes ); val->bv_len = len; if ( escapes == 0 ) { - val->bv_val = LDAP_STRNDUP( startPos, len ); + val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); } else { ber_len_t s, d; - val->bv_val = LDAP_MALLOC( len + 1 ); + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); val->bv_len = len; for ( s = d = 0; d < len; ) { @@ -1635,7 +1883,7 @@ hexstr2bin( const char *str, char *c ) } static int -hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags ) +hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len; @@ -1717,7 +1965,7 @@ end_of_value:; assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos )); val->bv_len = len; - val->bv_val = LDAP_MALLOC( len + 1 ); + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); if ( val->bv_val == NULL ) { return( LDAP_NO_MEMORY ); } @@ -1806,8 +2054,18 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len ) return( 0 ); } - for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) { - cl = LDAP_UTF8_CHARLEN( p ); + for ( l = 0, p = val->bv_val; p < val->bv_val + val->bv_len; p += cl ) { + + /* + * escape '%x00' + */ + if ( p[ 0 ] == '\0' ) { + cl = 1; + l += 3; + continue; + } + + cl = LDAP_UTF8_CHARLEN2( p, cl ); if ( cl == 0 ) { /* illegal utf-8 char! */ return( -1 ); @@ -1816,7 +2074,7 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len ) ber_len_t cnt; for ( cnt = 1; cnt < cl; cnt++ ) { - if ( ( p[ cnt ] & 0x80 ) == 0x00 ) { + if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) { return( -1 ); } } @@ -1826,7 +2084,11 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len ) || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) { #ifdef PRETTY_ESCAPE +#if 0 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) { +#else + if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) { +#endif /* * there might be some chars we want @@ -1875,7 +2137,26 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) * of the value */ for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) { - ber_len_t cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] ); + ber_len_t cl; + + /* + * escape '%x00' + */ + if ( val->bv_val[ s ] == '\0' ) { + cl = 1; + str[ d++ ] = '\\'; + str[ d++ ] = '0'; + str[ d++ ] = '0'; + s++; + continue; + } + + /* + * The length was checked in strval2strlen(); + * LDAP_UTF8_CHARLEN() should suffice + */ + cl = LDAP_UTF8_CHARLEN2( &val->bv_val[ s ], cl ); + assert( cl > 0 ); /* * there might be some chars we want to escape in form @@ -1883,7 +2164,11 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) */ if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) #ifdef PRETTY_ESCAPE +#if 0 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] ) +#else + || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] ) +#endif #else /* ! PRETTY_ESCAPE */ || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) @@ -2192,7 +2477,7 @@ strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) * by Luke Howard, http://www.padl.com/~lukeh) */ static int -dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN ) +dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN ) { int i; int domain = 0, first = 1; @@ -2210,14 +2495,14 @@ dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN ) str = bv->bv_val + pos; for ( i = *iRDN; i >= 0; i-- ) { - LDAPRDN *rdn; + LDAPRDN rdn; LDAPAVA *ava; - assert( dn[ 0 ][ i ] ); - rdn = dn[ 0 ][ i ]; + assert( dn[ i ] ); + rdn = dn[ i ]; - assert( rdn[ 0 ][ 0 ] ); - ava = rdn[ 0 ][ 0 ]; + assert( rdn[ 0 ] ); + ava = rdn[ 0 ]; if ( !LDAP_DN_IS_RDN_DC( rdn ) ) { break; @@ -2232,7 +2517,7 @@ dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN ) l += ava->la_value.bv_len; } else { - AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val, l); + AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l); AC_MEMCPY( str, ava->la_value.bv_val, ava->la_value.bv_len ); str[ ava->la_value.bv_len ] = '.'; @@ -2247,7 +2532,7 @@ dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN ) } static int -rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len, +rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len, int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) ) { int iAVA; @@ -2255,8 +2540,8 @@ rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len, *len = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; /* len(type) + '=' + '+' | ',' */ l += ava->la_attr.bv_len + 2; @@ -2282,14 +2567,14 @@ rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len, } static int -rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, +rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) ) { int iAVA; ber_len_t l = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, ava->la_attr.bv_len ); @@ -2313,7 +2598,7 @@ rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, } l += vl; } - str[ l++ ] = ( rdn[ 0 ][ iAVA + 1 ] ? '+' : ',' ); + str[ l++ ] = ( rdn[ iAVA + 1] ? '+' : ',' ); } *len = l; @@ -2322,26 +2607,23 @@ rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, } static int -rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) +rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; *len = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; /* len(type) + '=' + ',' | '/' */ l += ava->la_attr.bv_len + 2; - switch ( ava->la_flags ) { - case LDAP_AVA_BINARY: + if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the length */ l += 1 + 2 * ava->la_value.bv_len; - break; - - case LDAP_AVA_STRING: { + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; @@ -2349,11 +2631,6 @@ rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2363,13 +2640,13 @@ rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) } static int -rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) +rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first ) { int iAVA; ber_len_t l = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; if ( first ) { first = 0; @@ -2383,16 +2660,13 @@ rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) str[ l++ ] = '='; - switch ( ava->la_flags ) { - case LDAP_AVA_BINARY: + if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } l += 2 * ava->la_value.bv_len; - break; - - case LDAP_AVA_STRING: { + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; @@ -2400,11 +2674,6 @@ rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2414,7 +2683,7 @@ rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) } static int -rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) +rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; @@ -2424,11 +2693,11 @@ rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) *len = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; /* ' + ' | ', ' */ - l += ( rdn[ 0 ][ iAVA + 1 ] ? 3 : 2 ); + l += ( rdn[ iAVA + 1 ] ? 3 : 2 ); /* FIXME: are binary values allowed in UFN? */ if ( ava->la_flags & LDAP_AVA_BINARY ) { @@ -2452,13 +2721,13 @@ rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) } static int -rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len ) +rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; @@ -2477,7 +2746,7 @@ rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len ) l += vl; } - if ( rdn[ 0 ][ iAVA + 1 ]) { + if ( rdn[ iAVA + 1 ] ) { AC_MEMCPY( &str[ l ], " + ", 3 ); l += 3; @@ -2493,7 +2762,7 @@ rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len ) } static int -rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) +rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; @@ -2503,20 +2772,17 @@ rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) *len = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; /* ',' | '/' */ l++; /* FIXME: are binary values allowed in UFN? */ - switch ( ava->la_flags ) { - case LDAP_AVA_BINARY: + if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the value */ l += 1 + 2 * ava->la_value.bv_len; - break; - - case LDAP_AVA_STRING: { + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; @@ -2524,11 +2790,6 @@ rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2538,13 +2799,13 @@ rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) } static int -rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) +rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first ) { int iAVA; ber_len_t l = 0; - for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; if ( first ) { first = 0; @@ -2552,16 +2813,13 @@ rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) str[ l++ ] = ( iAVA ? ',' : '/' ); } - switch ( ava->la_flags ) { - case LDAP_AVA_BINARY: + if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } l += 2 * ava->la_value.bv_len; - break; - - case LDAP_AVA_STRING: { + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; @@ -2569,11 +2827,6 @@ rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2590,20 +2843,30 @@ rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) * this is wanted to reduce the allocation of temporary buffers. */ int -ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags ) +ldap_rdn2str( LDAPRDN rdn, char **str, unsigned flags ) { struct berval bv; int rc; assert( str ); - rc = ldap_rdn2bv( rdn, &bv, flags ); + if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) { + return LDAP_PARAM_ERROR; + } + + rc = ldap_rdn2bv_x( rdn, &bv, flags, NULL ); *str = bv.bv_val; return rc; } int -ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags ) +ldap_rdn2bv( LDAPRDN rdn, struct berval *bv, unsigned flags ) +{ + return ldap_rdn2bv_x( rdn, bv, flags, NULL ); +} + +int +ldap_rdn2bv_x( LDAPRDN rdn, struct berval *bv, unsigned flags, void *ctx ) { int rc, back; ber_len_t l; @@ -2614,7 +2877,7 @@ ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags ) bv->bv_val = NULL; if ( rdn == NULL ) { - bv->bv_val = LDAP_STRDUP( "" ); + bv->bv_val = LDAP_STRDUPX( "", ctx ); return( LDAP_SUCCESS ); } @@ -2625,39 +2888,39 @@ ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags ) switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) { - return( LDAP_OTHER ); + return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_LDAPV2: if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) { - return( LDAP_OTHER ); + return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_UFN: if ( rdn2UFNstrlen( rdn, flags, &l ) ) { - return( LDAP_OTHER ); + return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_DCE: if ( rdn2DCEstrlen( rdn, flags, &l ) ) { - return( LDAP_OTHER ); + return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_AD_CANONICAL: if ( rdn2ADstrlen( rdn, flags, &l ) ) { - return( LDAP_OTHER ); + return LDAP_DECODING_ERROR; } break; default: - return( LDAP_INVALID_DN_SYNTAX ); + return LDAP_PARAM_ERROR; } - bv->bv_val = LDAP_MALLOC( l + 1 ); + bv->bv_val = LDAP_MALLOCX( l + 1, ctx ); switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: @@ -2687,18 +2950,18 @@ ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags ) default: /* need at least one of the previous */ - return( LDAP_OTHER ); + return LDAP_PARAM_ERROR; } if ( rc ) { - ldap_memfree( bv->bv_val ); - return( LDAP_OTHER ); + LDAP_FREEX( bv->bv_val, ctx ); + return rc; } bv->bv_len = l - back; bv->bv_val[ bv->bv_len ] = '\0'; - return( LDAP_SUCCESS ); + return LDAP_SUCCESS; } /* @@ -2713,22 +2976,31 @@ ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags ) * c) what do we do when binary values must be converted in UTF/DCE/AD? * use binary encoded BER */ -int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags ) +int ldap_dn2str( LDAPDN dn, char **str, unsigned flags ) { struct berval bv; int rc; assert( str ); - rc = ldap_dn2bv( dn, &bv, flags ); + if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) { + return LDAP_PARAM_ERROR; + } + + rc = ldap_dn2bv_x( dn, &bv, flags, NULL ); *str = bv.bv_val; return rc; } -int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags ) +int ldap_dn2bv( LDAPDN dn, struct berval *bv, unsigned flags ) +{ + return ldap_dn2bv_x( dn, bv, flags, NULL ); +} + +int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx ) { int iRDN; - int rc = LDAP_OTHER; + int rc = LDAP_ENCODING_ERROR; ber_len_t len, l; /* stringifying helpers for LDAPv3/LDAPv2 */ @@ -2736,18 +3008,22 @@ int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags ) int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l ); assert( bv ); - bv->bv_len = 0; bv->bv_val = NULL; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ARGS, "=> ldap_dn2bv(%u)\n%s%s", + flags, "", "" ); +#else Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" ); +#endif /* * a null dn means an empty dn string * FIXME: better raise an error? */ if ( dn == NULL ) { - bv->bv_val = LDAP_STRDUP( "" ); + bv->bv_val = LDAP_STRDUPX( "", ctx ); return( LDAP_SUCCESS ); } @@ -2755,36 +3031,33 @@ int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags ) case LDAP_DN_FORMAT_LDAPV3: sv2l = strval2strlen; sv2s = strval2str; - goto got_funcs; + if( 0 ) { case LDAP_DN_FORMAT_LDAPV2: - sv2l = strval2IA5strlen; - sv2s = strval2IA5str; -got_funcs: - - for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { + sv2l = strval2IA5strlen; + sv2s = strval2IA5str; + } + + for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - - if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) { + if ( rdn2strlen( dn[ iRDN ], flags, &rdnl, sv2l ) ) { goto return_results; } len += rdnl; } - if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) { + if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } - for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { + for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - if ( rdn2str( rdn, &bv->bv_val[ l ], flags, + if ( rdn2str( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, sv2s ) ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } @@ -2804,7 +3077,6 @@ got_funcs: break; case LDAP_DN_FORMAT_UFN: { - /* * FIXME: quoting from RFC 1781: * @@ -2844,17 +3116,16 @@ got_funcs: int last_iRDN = -1; #endif /* DC_IN_UFN */ - for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { + for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) { + if ( rdn2UFNstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; #ifdef DC_IN_UFN - if ( LDAP_DN_IS_RDN_DC( rdn ) ) { + if ( LDAP_DN_IS_RDN_DC( dn[ iRDN ] ) ) { if ( leftmost_dc == -1 ) { leftmost_dc = iRDN; } @@ -2864,7 +3135,7 @@ got_funcs: #endif /* DC_IN_UFN */ } - if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) { + if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } @@ -2872,13 +3143,12 @@ got_funcs: #ifdef DC_IN_UFN if ( leftmost_dc == -1 ) { #endif /* DC_IN_UFN */ - for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { + for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t vl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], + if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &vl ) ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } @@ -2897,11 +3167,10 @@ got_funcs: for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) { ber_len_t vl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], + if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &vl ) ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } @@ -2909,7 +3178,7 @@ got_funcs: } if ( !dn2domain( dn, bv, l, &last_iRDN ) ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } @@ -2919,34 +3188,30 @@ got_funcs: #endif /* DC_IN_UFN */ rc = LDAP_SUCCESS; - break; - } - case LDAP_DN_FORMAT_DCE: + } break; - for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { + case LDAP_DN_FORMAT_DCE: + for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - - if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) { + if ( rdn2DCEstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; } - if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) { + if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } for ( l = 0; iRDN--; ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags, + if ( rdn2DCEstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, 0 ) ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } @@ -2962,7 +3227,8 @@ got_funcs: break; case LDAP_DN_FORMAT_AD_CANONICAL: { - + int trailing_slash = 1; + /* * Sort of UFN for DCE DNs: a slash ('/') separated * global->local DN with no types; strictly speaking, @@ -2977,31 +3243,31 @@ got_funcs: * * "microsoft.com/People/Bill,Gates" */ - for ( iRDN = 0, len = -1; dn[ 0 ][ iRDN ]; iRDN++ ) { + for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) { + if ( rdn2ADstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; } - if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) { + if ( ( bv->bv_val = LDAP_MALLOCX( len + 2, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } iRDN--; - if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) ) { + if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) != 0 ) { for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; + + trailing_slash = 0; - if ( rdn2ADstr( rdn, &bv->bv_val[ l ], + if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, 0 ) ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } @@ -3017,19 +3283,18 @@ got_funcs: * i.e. terminated by a domain component */ if ( flags & LDAP_DN_PEDANTIC ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; - rc = LDAP_INVALID_DN_SYNTAX; + rc = LDAP_ENCODING_ERROR; break; } for ( l = 0; iRDN >= 0 ; iRDN-- ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ 0 ][ iRDN ]; - if ( rdn2ADstr( rdn, &bv->bv_val[ l ], + if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, first ) ) { - LDAP_FREE( bv->bv_val ); + LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } @@ -3040,21 +3305,230 @@ got_funcs: } } + if ( trailing_slash ) { + bv->bv_val[ len ] = '/'; + len++; + } + bv->bv_len = len; bv->bv_val[ bv->bv_len ] = '\0'; + rc = LDAP_SUCCESS; - break; - } + } break; default: - return( LDAP_INVALID_DN_SYNTAX ); - + return LDAP_PARAM_ERROR; } +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, "<= ldap_dn2bv(%s,%u)=%d\n", + bv->bv_val, flags, rc ); +#else Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n", bv->bv_val, flags, rc ); +#endif + return_results:; return( rc ); } +#ifdef HAVE_TLS +#include +#include + +/* Convert a structured DN from an X.509 certificate into an LDAPV3 DN. + * x509_name must be an (X509_NAME *). If func is non-NULL, the + * constructed DN will use numeric OIDs to identify attributeTypes, + * and the func() will be invoked to rewrite the DN with the given + * flags. + * + * Otherwise the DN will use shortNames as defined in the OpenSSL + * library. + * + * It's preferable to let slapd do the OID to attributeType mapping, + * because the OpenSSL tables are known to have many typos in versions + * up to (at least) 0.9.6c. However, the LDAP client has no schema tables, + * so we're forced to use OpenSSL's mapping there. + * -- Howard Chu 2002-04-18 + */ + +int +ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func, + unsigned flags ) +{ + LDAPDN newDN; + LDAPRDN newRDN; + LDAPAVA *newAVA, *baseAVA; + X509_NAME_ENTRY *ne; + ASN1_OBJECT *obj; + ASN1_STRING *str; + char oids[8192], *oidptr = oids, *oidbuf = NULL; + void *ptrs[2048]; + int i, j, k = 0, navas, nrdns, rc = LDAP_SUCCESS; + int set = -1; + size_t dnsize, oidrem = sizeof(oids), oidsize = 0; + int csize; + + struct berval Val; + + assert( bv ); + bv->bv_len = 0; + bv->bv_val = NULL; + + /* Get the number of AVAs. This is not necessarily the same as + * the number of RDNs. + */ + navas = X509_NAME_entry_count( x509_name ); + + /* Get the last element, to see how many RDNs there are */ + ne = X509_NAME_get_entry( x509_name, navas - 1 ); + nrdns = ne->set + 1; + + /* Allocate the DN/RDN/AVA stuff as a single block */ + dnsize = sizeof(LDAPRDN) * (nrdns+1); + dnsize += sizeof(LDAPAVA *) * (navas+nrdns); + dnsize += sizeof(LDAPAVA) * navas; + if (dnsize > sizeof(ptrs)) { + newDN = (LDAPDN)LDAP_MALLOC( dnsize ); + if ( newDN == NULL ) + return LDAP_NO_MEMORY; + } else { + newDN = (LDAPDN)ptrs; + } + + newDN[nrdns] = NULL; + newRDN = (LDAPRDN)(newDN + nrdns+1); + newAVA = (LDAPAVA *)(newRDN + navas + nrdns); + baseAVA = newAVA; + + /* Retrieve RDNs in reverse order; LDAP is backwards from X.500. */ + for ( i = nrdns - 1, j = 0; i >= 0; i-- ) { + ne = X509_NAME_get_entry( x509_name, i ); + obj = X509_NAME_ENTRY_get_object( ne ); + str = X509_NAME_ENTRY_get_data( ne ); + + /* If set changed, move to next RDN */ + if ( set != ne->set ) { + /* If this is not the first time, end the + * previous RDN and advance. + */ + if ( j > 0 ) { + newRDN[k] = NULL; + newRDN += k+1; + } + newDN[j++] = newRDN; + + k = 0; + set = ne->set; + } + newAVA->la_private = NULL; + newAVA->la_flags = LDAP_AVA_STRING; + + if ( !func ) { + int n = OBJ_obj2nid( obj ); + + if (n == NID_undef) + goto get_oid; + newAVA->la_attr.bv_val = (char *)OBJ_nid2sn( n ); + newAVA->la_attr.bv_len = strlen( newAVA->la_attr.bv_val ); +#ifdef HAVE_EBCDIC + newAVA->la_attr.bv_val = LDAP_STRDUP( newAVA->la_attr.bv_val ); + __etoa( newAVA->la_attr.bv_val ); + newAVA->la_flags |= LDAP_AVA_FREE_ATTR; +#endif + } else { +get_oid: newAVA->la_attr.bv_val = oidptr; + newAVA->la_attr.bv_len = OBJ_obj2txt( oidptr, oidrem, obj, 1 ); +#ifdef HAVE_EBCDIC + __etoa( newAVA->la_attr.bv_val ); +#endif + oidptr += newAVA->la_attr.bv_len + 1; + oidrem -= newAVA->la_attr.bv_len + 1; + + /* Running out of OID buffer space? */ + if (oidrem < 128) { + if ( oidsize == 0 ) { + oidsize = sizeof(oids) * 2; + oidrem = oidsize; + oidbuf = LDAP_MALLOC( oidsize ); + if ( oidbuf == NULL ) goto nomem; + oidptr = oidbuf; + } else { + char *old = oidbuf; + oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 ); + if ( oidbuf == NULL ) goto nomem; + /* Buffer moved! Fix AVA pointers */ + if ( old != oidbuf ) { + LDAPAVA *a; + long dif = oidbuf - old; + + for (a=baseAVA; a<=newAVA; a++){ + if (a->la_attr.bv_val >= old && + a->la_attr.bv_val <= (old + oidsize)) + a->la_attr.bv_val += dif; + } + } + oidptr = oidbuf + oidsize - oidrem; + oidrem += oidsize; + oidsize *= 2; + } + } + } + Val.bv_val = (char *) str->data; + Val.bv_len = str->length; + switch( str->type ) { + case V_ASN1_UNIVERSALSTRING: + /* This uses 32-bit ISO 10646-1 */ + csize = 4; goto to_utf8; + case V_ASN1_BMPSTRING: + /* This uses 16-bit ISO 10646-1 */ + csize = 2; goto to_utf8; + case V_ASN1_T61STRING: + /* This uses 8-bit, assume ISO 8859-1 */ + csize = 1; +to_utf8: rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value ); + newAVA->la_flags |= LDAP_AVA_FREE_VALUE; + if (rc != LDAP_SUCCESS) goto nomem; + newAVA->la_flags = LDAP_AVA_NONPRINTABLE; + break; + case V_ASN1_UTF8STRING: + newAVA->la_flags = LDAP_AVA_NONPRINTABLE; + /* This is already in UTF-8 encoding */ + case V_ASN1_IA5STRING: + case V_ASN1_PRINTABLESTRING: + /* These are always 7-bit strings */ + newAVA->la_value = Val; + default: + ; + } + newRDN[k] = newAVA; + newAVA++; + k++; + } + newRDN[k] = NULL; + + if ( func ) { + rc = func( newDN, flags, NULL ); + if ( rc != LDAP_SUCCESS ) + goto nomem; + } + + rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL ); + +nomem: + for (;baseAVA < newAVA; baseAVA++) { + if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR) + LDAP_FREE( baseAVA->la_attr.bv_val ); + if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE) + LDAP_FREE( baseAVA->la_value.bv_val ); + } + + if ( oidsize != 0 ) + LDAP_FREE( oidbuf ); + if ( newDN != (LDAPDN) ptrs ) + LDAP_FREE( newDN ); + return rc; +} +#endif /* HAVE_TLS */ +