X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fgetdn.c;h=d43287172576ff1174dffff2afaf20f26ebb5137;hb=3d39ff68a94e4455074707d763138f01aaa1c5b1;hp=f2ebaa911c5a699493fa1b988ad0ba071503a8cb;hpb=4d981f7cc56aca0494769de2f4dad2abc67c0caa;p=openldap diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index f2ebaa911c..d432871725 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-2007 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. * - * getdn.c + * 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" @@ -15,34 +21,28 @@ #include #include - -#include #include #include #include #include "ldap-int.h" +#include "ldap_schema.h" /* 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 -static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout ); - -/* from libraries/libldap/schema.c */ -extern char * parse_numericoid(const char **sp, int *code, const int flags); - /* parsing/printing routines */ -static int str2strval( const char *str, struct berval **val, - const char **next, unsigned flags, unsigned *retFlags ); -static int DCE2strval( const char *str, struct berval **val, - const char **next, unsigned flags ); -static int IA52strval( const char *str, struct berval **val, - const char **next, unsigned flags ); -static int quotedIA52strval( const char *str, struct berval **val, - const char **next, unsigned flags ); -static int hexstr2binval( const char *str, struct berval **val, - const char **next, unsigned flags ); +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, void *ctx ); +static int IA52strval( const char *str, struct berval *val, + const char **next, unsigned flags, void *ctx ); +static int quotedIA52strval( const char *str, struct berval *val, + const char **next, unsigned flags, void *ctx ); +static int hexstr2binval( const char *str, struct berval *val, + 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 ); @@ -62,29 +62,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, char *str, 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 ); -static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava ); -static LDAPRDN * ldapava_insert_into_rdn( - LDAPRDN *rdn, LDAPAVA *ava, unsigned where ); -static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn ); -static LDAPDN * ldapava_insert_into_dn( - LDAPDN *dn, LDAPRDN *rdn, unsigned where ); + 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 @@ -97,10 +91,9 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry ) Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 ); - 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 ) { @@ -111,6 +104,53 @@ 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; + + Debug( LDAP_DEBUG_TRACE, "ldap_get_dn_ber\n", 0, 0, 0 ); + + 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 */ @@ -121,7 +161,8 @@ ldap_dn2ufn( LDAP_CONST char *dn ) Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 ); - ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN ); + ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, + &out, LDAP_DN_FORMAT_UFN ); return( out ); } @@ -132,7 +173,7 @@ 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; @@ -152,34 +193,30 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes ) return values; } - for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) { - char *str, **v = NULL; - - ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag ); + for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ); - v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) ); - if ( v == NULL ) { - LBER_VFREE( values ); - ldap_dnfree( tmpDN ); - return NULL; - } - values = v; - values[ iRDN ] = str; + values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) ); + if ( values == NULL ) { + ldap_dnfree( tmpDN ); + return NULL; } + for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) { + ldap_rdn2str( tmpDN[ iRDN ], &values[ iRDN ], flag ); + } + ldap_dnfree( tmpDN ); values[ iRDN ] = NULL; + return values; } char ** ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) { - LDAPRDN *tmpRDN; + LDAPRDN tmpRDN; char **values = NULL; const char *p; int iAVA; - unsigned flag = - notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3; Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 ); @@ -188,39 +225,40 @@ ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) * 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[ iAVA ]; iAVA++ ) ; + values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) ); + if ( values == NULL ) { + ldap_rdnfree( tmpRDN ); + return( NULL ); + } + for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) { ber_len_t l = 0, vl, al = 0; - char *str, **v = NULL; - LDAPAVA *ava = tmpRDN[ iAVA ][ 0 ]; - - v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) ); - if ( v == NULL ) { - goto error_return; - } - values = v; + char *str; + LDAPAVA *ava = tmpRDN[ iAVA ]; - if ( ava->la_flags == LDAP_AVA_BINARY ) { - vl = 1 + 2 * ava->la_value->bv_len; + if ( ava->la_flags & LDAP_AVA_BINARY ) { + vl = 1 + 2 * ava->la_value.bv_len; } else { - if ( strval2strlen( ava->la_value, + if ( strval2strlen( &ava->la_value, ava->la_flags, &vl ) ) { goto error_return; } } if ( !notypes ) { - al = ava->la_attr->bv_len; - l = vl + ava->la_attr->bv_len + 1; + al = ava->la_attr.bv_len; + l = vl + ava->la_attr.bv_len + 1; str = LDAP_MALLOC( l + 1 ); - AC_MEMCPY( str, ava->la_attr->bv_val, - ava->la_attr->bv_len ); + AC_MEMCPY( str, ava->la_attr.bv_val, + ava->la_attr.bv_len ); str[ al++ ] = '='; } else { @@ -228,14 +266,14 @@ 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 ] ) ) { + if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) { goto error_return; } } else { - if ( strval2str( ava->la_value, &str[ al ], + if ( strval2str( &ava->la_value, &str[ al ], ava->la_flags, &vl ) ) { goto error_return; } @@ -263,7 +301,8 @@ ldap_dn2dcedn( LDAP_CONST char *dn ) Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 ); - ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE ); + ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, + &out, LDAP_DN_FORMAT_DCE ); return( out ); } @@ -275,7 +314,7 @@ ldap_dcedn2dn( LDAP_CONST char *dce ) Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 ); - ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 ); + ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 ); return( out ); } @@ -287,46 +326,38 @@ ldap_dn2ad_canonical( LDAP_CONST char *dn ) Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 ); - ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, + ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_AD_CANONICAL ); return( out ); } -int -ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags ) -{ - assert( out ); - - Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 ); - - return dn2dn( in, iflags, out, oflags); -} - /* - * helper that changes the string representation of dnin + * function that changes the string representation of dnin * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK ) * * fin can be one of: - * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal, - * plus some rfc 1779) - * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis) - * LDAP_DN_FORMAT_LDAPV2 (rfc 1779) + * LDAP_DN_FORMAT_LDAP (RFC 4514 liberal, plus some RFC 1779) + * LDAP_DN_FORMAT_LDAPV3 (RFC 4514) + * LDAP_DN_FORMAT_LDAPV2 (RFC 1779) * LDAP_DN_FORMAT_DCE (?) * * fout can be any of the above except * LDAP_DN_FORMAT_LDAP * plus: - * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions) + * LDAP_DN_FORMAT_UFN (RFC 1781, partial and with extensions) * LDAP_DN_FORMAT_AD_CANONICAL (?) */ -static int -dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout ) +int +ldap_dn_normalize( LDAP_CONST char *dnin, + unsigned fin, char **dnout, unsigned fout ) { int rc; - LDAPDN *tmpDN = NULL; + LDAPDN tmpDN = NULL; + + Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 ); - assert( dnout ); + assert( dnout != NULL ); *dnout = NULL; @@ -364,28 +395,28 @@ dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout ) #define B4IA5VALUE 0x0040 #define B4BINARYVALUE 0x0050 -/* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */ +/* + * Helpers (mostly from slap.h) + * c is assumed to Unicode in an ASCII compatible format (UTF-8) + * Macros assume "C" Locale (ASCII) + */ #define LDAP_DN_ASCII_SPACE(c) \ ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' ) -#define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' ) -#define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' ) -#define LDAP_DN_ASCII_ALPHA(c) \ - ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) ) -#define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' ) -#define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' ) -#define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' ) -#define LDAP_DN_ASCII_HEXDIGIT(c) \ - ( LDAP_DN_ASCII_DIGIT(c) \ - || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \ - || LDAP_DN_ASCII_UCASE_HEXALPHA(c) ) -#define LDAP_DN_ASCII_ALNUM(c) \ - ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) ) +#define LDAP_DN_ASCII_LOWER(c) LDAP_LOWER(c) +#define LDAP_DN_ASCII_UPPER(c) LDAP_UPPER(c) +#define LDAP_DN_ASCII_ALPHA(c) LDAP_ALPHA(c) + +#define LDAP_DN_ASCII_DIGIT(c) LDAP_DIGIT(c) +#define LDAP_DN_ASCII_LCASE_HEXALPHA(c) LDAP_HEXLOWER(c) +#define LDAP_DN_ASCII_UCASE_HEXALPHA(c) LDAP_HEXUPPER(c) +#define LDAP_DN_ASCII_HEXDIGIT(c) LDAP_HEX(c) +#define LDAP_DN_ASCII_ALNUM(c) LDAP_ALNUM(c) #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' ) /* attribute type */ -#define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) ) -#define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) ) -#define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' ) +#define LDAP_DN_OID_LEADCHAR(c) LDAP_DIGIT(c) +#define LDAP_DN_DESC_LEADCHAR(c) LDAP_ALPHA(c) +#define LDAP_DN_DESC_CHAR(c) LDAP_LDH(c) #define LDAP_DN_LANG_SEP(c) ( (c) == ';' ) #define LDAP_DN_ATTRDESC_CHAR(c) \ ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) ) @@ -400,19 +431,34 @@ dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout ) #define LDAP_DN_ESCAPE(c) ( (c) == '\\' ) #define LDAP_DN_VALUE_END(c) \ ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) ) + +/* NOTE: according to RFC 4514, '=' can be escaped and treated as special, + * i.e. escaped both as "\" and * as "\=", but it is treated as + * a regular char, i.e. it can also appear as '='. + * + * As such, in 2.2 we used to allow reading unescaped '=', but we always + * produced escaped '\3D'; this changes since 2.3, if compatibility issues + * do not arise + */ #define LDAP_DN_NE(c) \ ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \ - || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' ) + || LDAP_DN_QUOTES(c) \ + || (c) == '<' || (c) == '>' ) +#define LDAP_DN_MAYESCAPE(c) \ + ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \ + || LDAP_DN_AVA_EQUALS(c) \ + || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) ) +#define LDAP_DN_SHOULDESCAPE(c) ( LDAP_DN_AVA_EQUALS(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) \ - ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) ) -#define LDAP_DN_IS_PRETTY( f ) ( (f) & LDAP_DN_PRETTY ) -#define LDAP_DN_WILLESCAPE(f, c) \ +#define LDAP_DN_WILLESCAPE_CHAR(c) \ + ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) ) +#define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY ) +#define LDAP_DN_WILLESCAPE_HEX(f, c) \ ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) ) /* LDAPv2 */ @@ -467,17 +513,23 @@ dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout ) /* generics */ #define LDAP_DN_HEXPAIR(s) \ ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) ) -#define LDAP_DC_ATTR "dc" /* better look at the AttributeDescription? */ /* FIXME: no composite rdn or non-"dc" types, right? * (what about "dc" in OID form?) */ /* FIXME: we do not allow binary values in domain, right? */ /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */ -#define LDAP_DN_IS_RDN_DC( rdn ) \ - ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \ - && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \ - && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) ) +/* NOTE: don't use strcasecmp() as it is locale specific! */ +#define LDAP_DC_ATTR "dc" +#define LDAP_DC_ATTRU "DC" +#define LDAP_DN_IS_RDN_DC( r ) \ + ( (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) \ @@ -504,35 +556,36 @@ dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout ) * LDAPAVA helpers (will become part of the API for operations * on structural representations of DNs). */ -LDAPAVA * +static 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 ); + assert( attr != NULL ); + assert( val != NULL ); - ava = LDAP_MALLOC( sizeof( LDAPAVA ) ); - - /* should we test it? */ - if ( ava == NULL ) { - return( NULL ); - } + ava = LDAP_MALLOCX( sizeof( LDAPAVA ) + attr->bv_len + 1, ctx ); + + 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_attr = ( struct berval * )attr; - ava->la_value = ( struct berval * )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 ); + assert( ava != NULL ); #if 0 /* ava's private must be freed by caller @@ -541,67 +594,20 @@ ldap_avafree( LDAPAVA *ava ) assert( ava->la_private == NULL ); #endif - ber_bvfree( ava->la_attr ); - ber_bvfree( ava->la_value ); - - LDAP_FREE( ava ); -} - -LDAPRDN * -ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava ) -{ - LDAPRDN *newRDN; - unsigned i = 0U; - - assert( ava ); - - if ( rdn != NULL ) { - for ( i = 0U; rdn[ i ]; i++ ) { - /* no op */ - } - } - newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) ); - newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) ); - newRDN[ i ][ 0 ] = ava; - newRDN[ i + 1 ] = NULL; + if (ava->la_flags & LDAP_AVA_FREE_VALUE) + LDAP_FREEX( ava->la_value.bv_val, ctx ); - return( newRDN ); + LDAP_FREEX( ava, ctx ); } -LDAPRDN * -ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where ) +void +ldap_rdnfree( LDAPRDN rdn ) { - LDAPRDN *newRDN; - unsigned i = 0U; - - assert( ava ); - - if ( rdn != NULL ) { - for ( i = 0U; rdn[ i ]; i++ ) { - /* no op */ - } - } - if ( where > i ) { - where = i; - /* assume "at end", which corresponds to - * ldapava_append_to_rdn */ - } - - newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) ); - - /* data after insert point */ - AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ], - ( i - where ) * sizeof( LDAPRDN * ) ); - - newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) ); - newRDN[ where ][ 0 ] = ava; - newRDN[ i + 1 ] = NULL; - - return( newRDN ); + ldap_rdnfree_x( rdn, NULL ); } void -ldap_rdnfree( LDAPRDN *rdn ) +ldap_rdnfree_x( LDAPRDN rdn, void *ctx ) { int iAVA; @@ -610,69 +616,20 @@ ldap_rdnfree( LDAPRDN *rdn ) } for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { - assert( rdn[ iAVA ][ 0 ] ); - - ldap_avafree( rdn[ iAVA ][ 0 ] ); + ldapava_free( rdn[ iAVA ], ctx ); } - LDAP_VFREE( rdn ); + LDAP_FREEX( rdn, ctx ); } -LDAPDN * -ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn ) +void +ldap_dnfree( LDAPDN dn ) { - LDAPDN *newDN; - unsigned i = 0U; - - assert( rdn ); - - if ( dn != NULL ) { - for ( i = 0U; dn[ i ]; i++ ) { - /* no op */ - } - } - newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) ); - newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) ); - newDN[ i ][ 0 ] = rdn; - newDN[ i + 1 ] = NULL; - - return( newDN ); -} - -LDAPDN * -ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where ) -{ - LDAPDN *newDN; - unsigned i = 0U; - - assert( rdn ); - - if ( dn != NULL ) { - for ( i = 0U; dn[ i ]; i++ ) { - /* no op */ - } - } - if ( where > i ) { - where = i; - /* assume "at end", which corresponds to - * ldapava_append_to_dn */ - } - - newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) ); - - /* data after insert point */ - AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ], - ( i - where ) * sizeof( LDAPDN * ) ); - - newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) ); - newDN[ where ][ 0 ] = rdn; - newDN[ i + 1 ] = NULL; - - return( newDN ); + ldap_dnfree_x( dn, NULL ); } void -ldap_dnfree( LDAPDN *dn ) +ldap_dnfree_x( LDAPDN dn, void *ctx ) { int iRDN; @@ -681,12 +638,10 @@ ldap_dnfree( LDAPDN *dn ) } for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) { - assert( dn[ iRDN ][ 0 ] ); - - ldap_rdnfree( dn[ iRDN ][ 0 ] ); + ldap_rdnfree_x( dn[ iRDN ], ctx ); } - LDAP_VFREE( dn ); + LDAP_FREEX( dn, ctx ); } /* @@ -703,40 +658,96 @@ ldap_dnfree( LDAPDN *dn ) * and readable as soon as it works as expected. */ +/* + * 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 ) { - const char *p; - int rc = LDAP_INVALID_DN_SYNTAX; + struct berval bv; + + assert( str != NULL ); - LDAPDN *newDN = NULL; - LDAPRDN *newRDN = NULL; + bv.bv_len = strlen( str ); + bv.bv_val = (char *) str; - assert( str ); - assert( dn ); + 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 *bvin, LDAPDN *dn, unsigned flags, void *ctx ) +{ + const char *p; + int rc = LDAP_DECODING_ERROR; + int nrdns = 0; + + LDAPDN newDN = NULL; + LDAPRDN newRDN = NULL, tmpDN_[TMP_RDN_SLOTS], *tmpDN = tmpDN_; + int num_slots = TMP_RDN_SLOTS; + char *str, *end; + struct berval bvtmp, *bv = &bvtmp; + + assert( bvin != NULL ); + assert( bvin->bv_val != NULL ); + assert( dn != NULL ); + + *bv = *bvin; + str = bv->bv_val; + end = str + bv->bv_len; - Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" ); + Debug( LDAP_DEBUG_ARGS, "=> ldap_bv2dn(%s,%u)\n", str, flags, 0 ); *dn = NULL; switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV3: - case LDAP_DN_FORMAT_LDAPV2: case LDAP_DN_FORMAT_DCE: break; + /* allow DN enclosed in brackets */ + case LDAP_DN_FORMAT_LDAPV2: + if ( str[0] == '<' ) { + if ( bv->bv_len < 2 || end[ -1 ] != '>' ) { + rc = LDAP_DECODING_ERROR; + goto parsing_error; + } + bv->bv_val++; + bv->bv_len -= 2; + str++; + end--; + } + break; + /* 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; @@ -750,7 +761,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 @@ -759,13 +775,16 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) flags |= LDAP_DN_FORMAT_DCE; p++; } +#endif } - for ( ; p[ 0 ]; p++ ) { - LDAPDN *dn; + 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; } @@ -773,11 +792,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; @@ -785,14 +804,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; @@ -800,44 +819,78 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags ) } - if ( LDAP_DN_DCE( flags ) ) { - /* add in reversed order */ - dn = ldapava_insert_into_dn( newDN, newRDN, 0 ); - } else { - dn = ldapava_append_to_dn( newDN, newRDN ); - } + tmpDN[nrdns++] = newRDN; + newRDN = NULL; - if ( dn == NULL ) { - rc = LDAP_NO_MEMORY; - goto parsing_error; - } + /* + * make the static RDN array dynamically rescalable + */ + if ( nrdns == num_slots ) { + LDAPRDN *tmp; - newDN = dn; - newRDN = NULL; + 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 */ - rc = LDAP_SUCCESS; + newDN = (LDAPDN)LDAP_MALLOCX( sizeof(LDAPRDN *) * (nrdns+1), ctx ); + if ( newDN == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } else { + int i; + + if ( LDAP_DN_DCE( flags ) ) { + /* add in reversed order */ + for ( i=0; i= 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 ); + } + + Debug( LDAP_DEBUG_ARGS, "<= ldap_bv2dn(%s)=%d %s\n", str, rc, + rc ? ldap_err2string( rc ) : "" ); *dn = newDN; return( rc ); @@ -852,26 +905,61 @@ 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 != NULL ); + 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 = NULL; - struct berval *attrValue = NULL; + struct berval attrType = BER_BVNULL; + struct berval attrValue = BER_BVNULL; + + LDAPRDN newRDN = NULL; + LDAPAVA *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_; + int num_slots = TMP_AVA_SLOTS; - LDAPRDN *newRDN = NULL; + char *str; + ber_len_t stoplen; - assert( str ); - assert( rdn ); - assert( n ); + assert( bv != NULL ); + assert( bv->bv_len != 0 ); + assert( bv->bv_val != NULL ); + assert( rdn || flags & LDAP_DN_SKIP ); + assert( n != NULL ); - Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" ); + str = bv->bv_val; + stoplen = bv->bv_len; - *rdn = NULL; + if ( rdn ) { + *rdn = NULL; + } *n = NULL; switch ( LDAP_DN_FORMAT( flags ) ) { @@ -884,14 +972,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; @@ -907,15 +1002,8 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) * an AttributeType can be encoded as: * - its string representation; in detail, implementations * MUST recognize AttributeType string type names listed - * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and - * MAY recognize other names. - * - its numeric OID (a dotted decimal string); in detail - * RFC 2253 asserts that ``Implementations MUST allow - * an oid in the attribute type to be prefixed by one - * of the character strings "oid." or "OID."''. As soon - * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253 - * I'm not sure whether this is required or not any - * longer; to be liberal, we still implement it. + * in Section 3 of RFC 4514, and MAY recognize other names. + * - its numeric OID (a dotted decimal string) */ case B4AVA: if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) { @@ -982,19 +1070,15 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) case B4OIDATTRTYPE: { int err = LDAP_SUCCESS; - char *type; - type = parse_numericoid( &p, &err, 0 ); - if ( type == NULL ) { - goto parsing_error; - } - attrType = LDAP_MALLOC( sizeof( struct berval ) ); - if ( attrType== NULL ) { - rc = LDAP_NO_MEMORY; + attrType.bv_val = ldap_int_parse_numericoid( &p, &err, + LDAP_SCHEMA_SKIP); + + if ( err != LDAP_SUCCESS ) { goto parsing_error; } - attrType->bv_val = type; - attrType->bv_len = strlen( type ); + attrType.bv_len = p - attrType.bv_val; + attrTypeEncoding = LDAP_AVA_BINARY; state = B4AVAEQUALS; @@ -1019,9 +1103,8 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) { /* - * RFC 2253 does not explicitly - * allow lang extensions to attribute - * types in DNs ... + * RFC 4514 explicitly does not allow attribute + * description options, such as language tags. */ if ( flags & LDAP_DN_PEDANTIC ) { goto parsing_error; @@ -1046,18 +1129,6 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) goto parsing_error; } - assert( attrType == NULL ); - attrType = LDAP_MALLOC( sizeof( struct berval ) ); - if ( attrType == NULL ) { - rc = LDAP_NO_MEMORY; - goto parsing_error; - } - attrType->bv_val = LDAP_STRNDUP( startPos, len ); - if ( attrType->bv_val == NULL ) { - rc = LDAP_NO_MEMORY; - goto parsing_error; - } - attrType->bv_len = len; attrTypeEncoding = LDAP_AVA_STRING; /* @@ -1067,6 +1138,14 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) */ state = B4AVAEQUALS; + + if ( flags & LDAP_DN_SKIP ) { + break; + } + + attrType.bv_val = (char *)startPos; + attrType.bv_len = len; + break; } @@ -1145,14 +1224,19 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) } /* - * here STRING means RFC 2253 string + * here STRING means RFC 4514 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; } @@ -1163,14 +1247,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; @@ -1183,7 +1268,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; } @@ -1194,7 +1279,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; } @@ -1202,26 +1287,51 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) break; case GOTAVA: { - LDAPAVA *ava; - LDAPRDN *rdn; int rdnsep = 0; - /* - * we accept empty values - */ - ava = ldapava_new( attrType, attrValue, - attrValueEncoding ); - if ( ava == NULL ) { - rc = LDAP_NO_MEMORY; - goto parsing_error; - } + if ( !( flags & LDAP_DN_SKIP ) ) { + LDAPAVA *ava; - rdn = ldapava_append_to_rdn( newRDN, ava ); - if ( rdn == NULL ) { - rc = LDAP_NO_MEMORY; - goto parsing_error; + /* + * we accept empty values + */ + ava = ldapava_new( &attrType, &attrValue, + attrValueEncoding, ctx ); + if ( ava == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + tmpRDN[navas++] = ava; + + 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; + } } - newRDN = rdn; /* * if we got an AVA separator ('+', or ',' for DCE ) @@ -1249,13 +1359,25 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) * the RDN is over, phew */ *n = p; + if ( !( flags & LDAP_DN_SKIP ) ) { + newRDN = (LDAPRDN)LDAP_MALLOCX( + sizeof(LDAPAVA) * (navas+1), ctx ); + if ( newRDN == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } else { + AC_MEMCPY( newRDN, tmpRDN, sizeof(LDAPAVA *) * navas); + newRDN[navas] = NULL; + } + + } rc = LDAP_SUCCESS; goto return_result; } /* they should have been used in an AVA */ - attrType = NULL; - attrValue = NULL; + attrType.bv_val = NULL; + attrValue.bv_val = NULL; p++; state = B4AVA; @@ -1267,27 +1389,28 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags ) goto parsing_error; } } + *n = p; parsing_error:; /* They are set to NULL after they're used in an AVA */ - if ( attrType ) { - ber_bvfree( attrType ); - } - if ( attrValue ) { - ber_bvfree( attrValue ); + if ( attrValue.bv_val ) { + LDAP_FREEX( attrValue.bv_val, ctx ); } - if ( newRDN ) { - ldap_rdnfree( newRDN ); - newRDN = NULL; + for ( navas-- ; navas >= 0; navas-- ) { + ldapava_free( tmpRDN[navas], ctx ); } return_result:; - Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n", - *n - p, str, rc ); - *rdn = newRDN; + if ( tmpRDN != tmpRDN_ ) { + LDAP_FREEX( tmpRDN, ctx ); + } + + if ( rdn ) { + *rdn = newRDN; + } return( rc ); } @@ -1298,27 +1421,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 ); + assert( str != NULL ); + assert( val != NULL ); + assert( next != NULL ); - *val = NULL; *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; } @@ -1345,14 +1465,18 @@ str2strval( const char *str, struct berval **val, const char **next, unsigned fl 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 ] ) ) ) { @@ -1387,71 +1511,71 @@ str2strval( const char *str, struct berval **val, const char **next, unsigned fl } } + *next = p; + if ( flags & LDAP_DN_SKIP ) { + return( 0 ); + } + /* * FIXME: test memory? */ - len = ( endPos ? endPos : p ) - startPos - escapes - unescapes; - *val = LDAP_MALLOC( sizeof( struct berval ) ); - ( *val )->bv_len = len; + 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 ] ) ) { - ( *val )->bv_val[ d++ ] = + if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) { + val->bv_val[ d++ ] = startPos[ s++ ]; } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) { char c; hexstr2bin( &startPos[ s ], &c ); - ( *val )->bv_val[ d++ ] = c; + val->bv_val[ d++ ] = c; 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 { - ( *val )->bv_val[ d++ ] = startPos[ s++ ]; + val->bv_val[ d++ ] = startPos[ s++ ]; } } - ( *val )->bv_val[ d ] = '\0'; - assert( strlen( ( *val )->bv_val ) == len ); + val->bv_val[ d ] = '\0'; + assert( d == len ); } - - *next = p; - 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; - assert( str ); - assert( val ); - assert( next ); + assert( str != NULL ); + assert( val != NULL ); + assert( next != NULL ); - *val = NULL; *next = NULL; for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) { @@ -1494,17 +1618,20 @@ DCE2strval( const char *str, struct berval **val, const char **next, unsigned fl } } - + *next = p; + if ( flags & LDAP_DN_SKIP ) { + return( 0 ); + } + len = ( endPos ? endPos : p ) - startPos - escapes; - *val = LDAP_MALLOC( sizeof( struct berval ) ); - ( *val )->bv_len = len; + 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 @@ -1515,28 +1642,25 @@ DCE2strval( const char *str, struct berval **val, const char **next, unsigned fl s++; } - ( *val )->bv_val[ d++ ] = startPos[ s++ ]; + val->bv_val[ d++ ] = startPos[ s++ ]; } - ( *val )->bv_val[ d ] = '\0'; - assert( strlen( ( *val )->bv_val ) == len ); + val->bv_val[ d ] = '\0'; + assert( strlen( val->bv_val ) == len ); } - *next = p; - return( 0 ); } 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; - assert( str ); - assert( val ); - assert( next ); + assert( str != NULL ); + assert( val != NULL ); + assert( next != NULL ); - *val = NULL; *next = NULL; /* @@ -1575,42 +1699,44 @@ IA52strval( const char *str, struct berval **val, const char **next, unsigned fl /* no op */ } - *val = LDAP_MALLOC( sizeof( struct berval ) ); + *next = p; + if ( flags & LDAP_DN_SKIP ) { + return( 0 ); + } + len = ( endPos ? endPos : p ) - startPos - escapes; - ( *val )->bv_len = len; + 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++; } - ( *val )->bv_val[ d++ ] = startPos[ s++ ]; + val->bv_val[ d++ ] = startPos[ s++ ]; } - ( *val )->bv_val[ d ] = '\0'; - assert( strlen( ( *val )->bv_val ) == len ); + val->bv_val[ d ] = '\0'; + assert( strlen( val->bv_val ) == len ); } - *next = p; return( 0 ); } 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; unsigned escapes = 0; - assert( str ); - assert( val ); - assert( next ); + assert( str != NULL ); + assert( val != NULL ); + assert( next != NULL ); - *val = NULL; *next = NULL; /* initial quote already eaten */ @@ -1662,31 +1788,33 @@ quotedIA52strval( const char *str, struct berval **val, const char **next, unsig /* no op */ } + *next = p; + if ( flags & LDAP_DN_SKIP ) { + return( 0 ); + } + len = endPos - startPos - escapes; - assert( len >= 0 ); - *val = LDAP_MALLOC( sizeof( struct berval ) ); - ( *val )->bv_len = len; + 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_len = len; + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); + val->bv_len = len; for ( s = d = 0; d < len; ) { if ( LDAP_DN_ESCAPE( str[ s ] ) ) { s++; } - ( *val )->bv_val[ d++ ] = str[ s++ ]; + val->bv_val[ d++ ] = str[ s++ ]; } - ( *val )->bv_val[ d ] = '\0'; - assert( strlen( ( *val )->bv_val ) == len ); + val->bv_val[ d ] = '\0'; + assert( strlen( val->bv_val ) == len ); } - *next = p; - return( 0 ); } @@ -1695,8 +1823,8 @@ hexstr2bin( const char *str, char *c ) { char c1, c2; - assert( str ); - assert( c ); + assert( str != NULL ); + assert( c != NULL ); c1 = str[ 0 ]; c2 = str[ 1 ]; @@ -1705,9 +1833,10 @@ hexstr2bin( const char *str, char *c ) *c = c1 - '0'; } else { - c1 = tolower( c1 ); - - if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) { + if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) { + *c = c1 - 'A' + 10; + } else { + assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ); *c = c1 - 'a' + 10; } } @@ -1718,9 +1847,10 @@ hexstr2bin( const char *str, char *c ) *c += c2 - '0'; } else { - c2 = tolower( c2 ); - - if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) { + if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) { + *c += c2 - 'A' + 10; + } else { + assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ); *c += c2 - 'a' + 10; } } @@ -1729,17 +1859,16 @@ 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; ber_len_t s, d; - assert( str ); - assert( val ); - assert( next ); + assert( str != NULL ); + assert( val != NULL ); + assert( next != NULL ); - *val = NULL; *next = NULL; for ( startPos = p = str; p[ 0 ]; p += 2 ) { @@ -1802,19 +1931,18 @@ hexstr2binval( const char *str, struct berval **val, const char **next, unsigned end_of_value:; + *next = p; + if ( flags & LDAP_DN_SKIP ) { + return( 0 ); + } + len = ( ( endPos ? endPos : p ) - startPos ) / 2; /* must be even! */ assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos )); - *val = LDAP_MALLOC( sizeof( struct berval ) ); - if ( *val == NULL ) { - return( LDAP_NO_MEMORY ); - } - - ( *val )->bv_len = len; - ( *val )->bv_val = LDAP_MALLOC( len + 1 ); - if ( ( *val )->bv_val == NULL ) { - LDAP_FREE( *val ); + val->bv_len = len; + val->bv_val = LDAP_MALLOCX( len + 1, ctx ); + if ( val->bv_val == NULL ) { return( LDAP_NO_MEMORY ); } @@ -1823,11 +1951,10 @@ end_of_value:; hexstr2bin( &startPos[ s ], &c ); - ( *val )->bv_val[ d ] = c; + val->bv_val[ d ] = c; } - ( *val )->bv_val[ d ] = '\0'; - *next = p; + val->bv_val[ d ] = '\0'; return( 0 ); } @@ -1838,10 +1965,10 @@ end_of_value:; static int byte2hexpair( const char *val, char *pair ) { - static const char hexdig[] = "0123456789abcdef"; + static const char hexdig[] = "0123456789ABCDEF"; - assert( val ); - assert( pair ); + assert( val != NULL ); + assert( pair != NULL ); /* * we assume the string has enough room for the hex encoding @@ -1862,8 +1989,8 @@ binval2hexstr( struct berval *val, char *str ) { ber_len_t s, d; - assert( val ); - assert( str ); + assert( val != NULL ); + assert( str != NULL ); if ( val->bv_len == 0 ) { return( 0 ); @@ -1889,19 +2016,33 @@ static int strval2strlen( struct berval *val, unsigned flags, ber_len_t *len ) { ber_len_t l, cl = 1; - char *p; + char *p, *end; int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3; +#ifdef PRETTY_ESCAPE + int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3; +#endif /* PRETTY_ESCAPE */ - assert( val ); - assert( len ); + assert( val != NULL ); + assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { return( 0 ); } - for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) { - cl = ldap_utf8_charlen( p ); + end = val->bv_val + val->bv_len - 1; + for ( l = 0, p = val->bv_val; p <= end; 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 ); @@ -1910,23 +2051,36 @@ 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 ); } } l += escaped_byte_len * cl; - - /* - * there might be some chars we want to escape in form - * of a couple of hexdigits for optimization purposes - */ - } else if ( LDAP_DN_WILLESCAPE( flags, p[ 0 ] ) ) { - l += 3; } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) + || LDAP_DN_SHOULDESCAPE( p[ 0 ] ) || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) - || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) { - l += 2; + || ( p == end && 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 + * to escape in form of a couple + * of hexdigits for optimization purposes + */ + l += 3; + + } else { + l += escaped_ascii_len; + } +#else /* ! PRETTY_ESCAPE */ + l += 3; +#endif /* ! PRETTY_ESCAPE */ } else { l++; @@ -1947,9 +2101,9 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { ber_len_t s, d, end; - assert( val ); - assert( str ); - assert( len ); + assert( val != NULL ); + assert( str != NULL ); + assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; @@ -1961,14 +2115,46 @@ 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 * of a couple of hexdigits for optimization purposes */ if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) - || LDAP_DN_WILLESCAPE( flags, val->bv_val[ s ] ) ) { +#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 ] ) + || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) + || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) + || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) + +#endif /* ! PRETTY_ESCAPE */ + ) { for ( ; cl--; ) { str[ d++ ] = '\\'; byte2hexpair( &val->bv_val[ s ], &str[ d ] ); @@ -1982,11 +2168,20 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) } } else { +#ifdef PRETTY_ESCAPE if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) + || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) { str[ d++ ] = '\\'; + if ( !LDAP_DN_IS_PRETTY( flags ) ) { + byte2hexpair( &val->bv_val[ s ], &str[ d ] ); + s++; + d += 2; + continue; + } } +#endif /* PRETTY_ESCAPE */ str[ d++ ] = val->bv_val[ s++ ]; } } @@ -2005,8 +2200,8 @@ strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len ) ber_len_t l; char *p; - assert( val ); - assert( len ); + assert( val != NULL ); + assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { @@ -2022,6 +2217,7 @@ strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len ) } else { for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) { if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) + || LDAP_DN_SHOULDESCAPE( p[ 0 ] ) || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) { l += 2; @@ -2046,9 +2242,9 @@ strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { ber_len_t s, d, end; - assert( val ); - assert( str ); - assert( len ); + assert( val != NULL ); + assert( str != NULL ); + assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; @@ -2070,6 +2266,7 @@ strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) { if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) + || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) { str[ d++ ] = '\\'; @@ -2093,8 +2290,8 @@ strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len ) ber_len_t l; char *p; - assert( val ); - assert( len ); + assert( val != NULL ); + assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { @@ -2133,9 +2330,9 @@ strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { ber_len_t s, d; - assert( val ); - assert( str ); - assert( len ); + assert( val != NULL ); + assert( str != NULL ); + assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; @@ -2171,81 +2368,71 @@ strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) /* * Length of the (supposedly) AD canonical string representation, - * accounting for escaped hex of UTF-8 chars + * accounting for chars that need to be escaped */ static int strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len ) { - ber_len_t l; + ber_len_t l, cl; char *p; - assert( val ); - assert( len ); + assert( val != NULL ); + assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { return( 0 ); } - if ( flags & LDAP_AVA_NONPRINTABLE ) { - /* - * FIXME: Turn the value into a binary encoded BER? - */ - return( -1 ); - - } else { - for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) { - if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) { - l += 2; - - } else { - l++; - } + for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) { + cl = LDAP_UTF8_CHARLEN2( p, cl ); + if ( cl == 0 ) { + /* illegal utf-8 char */ + return -1; + } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) { + l += 2; + } else { + l += cl; } } *len = l; - + return( 0 ); } /* - * convert to (supposedly) AD string representation, - * escaping with hex the UTF-8 stuff; + * convert to (supposedly) AD string representation, * assume the destination has enough room for escaping */ static int strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { - ber_len_t s, d; + ber_len_t s, d, cl; - assert( val ); - assert( str ); - assert( len ); + assert( val != NULL ); + assert( str != NULL ); + assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; return( 0 ); } - if ( flags & LDAP_AVA_NONPRINTABLE ) { - /* - * FIXME: Turn the value into a binary encoded BER? - */ - *len = 0; - return( -1 ); - - } else { - - /* - * we assume the string has enough room for the hex encoding - * of the value - */ + /* + * we assume the string has enough room for the escaping + * of the value + */ - for ( s = 0, d = 0; s < val->bv_len; ) { - if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) { - str[ d++ ] = '\\'; - } + for ( s = 0, d = 0; s < val->bv_len; ) { + cl = LDAP_UTF8_CHARLEN2( val->bv_val+s, cl ); + if ( cl == 0 ) { + /* illegal utf-8 char */ + return -1; + } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD(val->bv_val[ s ]) ) { + str[ d++ ] = '\\'; + } + for (; cl--;) { str[ d++ ] = val->bv_val[ s++ ]; } } @@ -2257,34 +2444,37 @@ strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) /* * If the DN is terminated by single-AVA RDNs with attribute type of "dc", - * the forst part of the AD representation of the DN is written in DNS + * the first part of the AD representation of the DN is written in DNS * form, i.e. dot separated domain name components (as suggested * by Luke Howard, http://www.padl.com/~lukeh) */ static int -dn2domain( LDAPDN *dn, char *str, int *iRDN ) +dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN ) { int i; int domain = 0, first = 1; ber_len_t l = 1; /* we move the null also */ + char *str; /* we are guaranteed there's enough memory in str */ /* sanity */ - assert( dn ); - assert( str ); - assert( iRDN ); - assert( *iRDN > 0 ); + assert( dn != NULL ); + assert( bv != NULL ); + assert( iRDN != NULL ); + assert( *iRDN >= 0 ); + + str = bv->bv_val + pos; for ( i = *iRDN; i >= 0; i-- ) { - LDAPRDN *rdn; + LDAPRDN rdn; LDAPAVA *ava; - assert( dn[ i ][ 0 ] ); - rdn = dn[ i ][ 0 ]; + assert( dn[ i ] != NULL ); + rdn = dn[ i ]; - assert( rdn[ 0 ][ 0 ] ); - ava = rdn[ 0 ][ 0 ]; + assert( rdn[ 0 ] != NULL ); + ava = rdn[ 0 ]; if ( !LDAP_DN_IS_RDN_DC( rdn ) ) { break; @@ -2294,26 +2484,27 @@ dn2domain( LDAPDN *dn, char *str, int *iRDN ) if ( first ) { first = 0; - AC_MEMCPY( str, ava->la_value->bv_val, - ava->la_value->bv_len + 1); - l += ava->la_value->bv_len; + AC_MEMCPY( str, ava->la_value.bv_val, + ava->la_value.bv_len + 1); + l += ava->la_value.bv_len; } else { - AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l); - AC_MEMCPY( str, ava->la_value->bv_val, - ava->la_value->bv_len ); - str[ ava->la_value->bv_len ] = '.'; - l += ava->la_value->bv_len + 1; + 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 ] = '.'; + l += ava->la_value.bv_len + 1; } } *iRDN = i; + bv->bv_len = pos + l - 1; return( domain ); } 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; @@ -2322,20 +2513,20 @@ rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len, *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + LDAPAVA *ava = rdn[ iAVA ]; /* len(type) + '=' + '+' | ',' */ - l += ava->la_attr->bv_len + 2; + l += ava->la_attr.bv_len + 2; if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the length */ - l += 1 + 2 * ava->la_value->bv_len; + l += 1 + 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( ( *s2l )( ava->la_value, f, &vl ) ) { + if ( ( *s2l )( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; @@ -2348,38 +2539,38 @@ 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[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + LDAPAVA *ava = rdn[ iAVA ]; - AC_MEMCPY( &str[ l ], ava->la_attr->bv_val, - ava->la_attr->bv_len ); - l += ava->la_attr->bv_len; + AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, + ava->la_attr.bv_len ); + l += ava->la_attr.bv_len; str[ l++ ] = '='; if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; - if ( binval2hexstr( ava->la_value, &str[ l ] ) ) { + if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } - l += 2 * ava->la_value->bv_len; + l += 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) { + if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; } - str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' ); + str[ l++ ] = ( rdn[ iAVA + 1] ? '+' : ',' ); } *len = l; @@ -2388,7 +2579,7 @@ 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; @@ -2396,30 +2587,22 @@ rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + LDAPAVA *ava = rdn[ iAVA ]; /* len(type) + '=' + ',' | '/' */ - l += ava->la_attr->bv_len + 2; + 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: { + l += 1 + 2 * ava->la_value.bv_len; + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) { + if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2429,13 +2612,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[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + LDAPAVA *ava = rdn[ iAVA ]; if ( first ) { first = 0; @@ -2443,34 +2626,26 @@ rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first ) str[ l++ ] = ( iAVA ? ',' : '/' ); } - AC_MEMCPY( &str[ l ], ava->la_attr->bv_val, - ava->la_attr->bv_len ); - l += ava->la_attr->bv_len; + AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, + ava->la_attr.bv_len ); + l += ava->la_attr.bv_len; 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 ] ) ) { + if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } - l += 2 * ava->la_value->bv_len; - break; - - case LDAP_AVA_STRING: { + l += 2 * ava->la_value.bv_len; + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) { + if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2480,18 +2655,18 @@ 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; - assert( rdn ); - assert( len ); + assert( rdn != NULL ); + assert( len != NULL ); *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + LDAPAVA *ava = rdn[ iAVA ]; /* ' + ' | ', ' */ l += ( rdn[ iAVA + 1 ] ? 3 : 2 ); @@ -2499,13 +2674,13 @@ rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len ) /* FIXME: are binary values allowed in UFN? */ if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the value */ - l += 1 + 2 * ava->la_value->bv_len; + l += 1 + 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( strval2strlen( ava->la_value, f, &vl ) ) { + if ( strval2strlen( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; @@ -2518,32 +2693,32 @@ 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[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + LDAPAVA *ava = rdn[ iAVA ]; if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; - if ( binval2hexstr( ava->la_value, &str[ l ] ) ) { + if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } - l += 2 * ava->la_value->bv_len; + l += 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) { + if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; } - if ( rdn[ iAVA + 1 ]) { + if ( rdn[ iAVA + 1 ] ) { AC_MEMCPY( &str[ l ], " + ", 3 ); l += 3; @@ -2559,42 +2734,34 @@ 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; - assert( rdn ); - assert( len ); + assert( rdn != NULL ); + assert( len != NULL ); *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + 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: { + l += 1 + 2 * ava->la_value.bv_len; + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( strval2ADstrlen( ava->la_value, f, &vl ) ) { + if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2604,13 +2771,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[ iAVA ]; iAVA++ ) { - LDAPAVA *ava = rdn[ iAVA ][ 0 ]; + LDAPAVA *ava = rdn[ iAVA ]; if ( first ) { first = 0; @@ -2618,28 +2785,20 @@ 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 ] ) ) { + if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } - l += 2 * ava->la_value->bv_len; - break; - - case LDAP_AVA_STRING: { + l += 2 * ava->la_value.bv_len; + } else { ber_len_t vl; unsigned f = flags | ava->la_flags; - if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) { + if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; - break; - } - - default: - return( -1 ); } } @@ -2656,15 +2815,41 @@ 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 != NULL ); + + 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 ) +{ + 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; - assert( str ); + assert( bv != NULL ); + + bv->bv_len = 0; + bv->bv_val = NULL; if ( rdn == NULL ) { - *str = LDAP_STRDUP( "" ); + bv->bv_val = LDAP_STRDUPX( "", ctx ); return( LDAP_SUCCESS ); } @@ -2672,83 +2857,83 @@ ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags ) * This routine wastes "back" bytes at the end of the string */ - *str = NULL; 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; } - *str = LDAP_MALLOC( l + 1 ); + bv->bv_val = LDAP_MALLOCX( l + 1, ctx ); switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: - rc = rdn2str( rdn, *str, flags, &l, strval2str ); + rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str ); back = 1; break; case LDAP_DN_FORMAT_LDAPV2: - rc = rdn2str( rdn, *str, flags, &l, strval2IA5str ); + rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str ); back = 1; break; case LDAP_DN_FORMAT_UFN: - rc = rdn2UFNstr( rdn, *str, flags, &l ); + rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l ); back = 2; break; case LDAP_DN_FORMAT_DCE: - rc = rdn2DCEstr( rdn, *str, flags, &l, 1 ); + rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 ); back = 0; break; case LDAP_DN_FORMAT_AD_CANONICAL: - rc = rdn2ADstr( rdn, *str, flags, &l, 1 ); + rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 ); back = 0; break; default: /* need at least one of the previous */ - return( LDAP_OTHER ); + return LDAP_PARAM_ERROR; } if ( rc ) { - ldap_memfree( *str ); - return( LDAP_OTHER ); + LDAP_FREEX( bv->bv_val, ctx ); + return rc; } - ( *str )[ l - back ] = '\0'; + bv->bv_len = l - back; + bv->bv_val[ bv->bv_len ] = '\0'; - return( LDAP_SUCCESS ); + return LDAP_SUCCESS; } /* @@ -2763,28 +2948,49 @@ ldap_rdn2str( LDAPRDN *rdn, char **str, 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 != NULL ); + + 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 ) +{ + 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 */ int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l ); int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l ); - assert( str ); + assert( bv != NULL ); + bv->bv_len = 0; + bv->bv_val = NULL; - Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" ); - - *str = NULL; + Debug( LDAP_DEBUG_ARGS, "=> ldap_dn2bv(%u)\n", flags, 0, 0 ); /* * a null dn means an empty dn string * FIXME: better raise an error? */ if ( dn == NULL ) { - *str = LDAP_STRDUP( "" ); + bv->bv_val = LDAP_STRDUPX( "", ctx ); return( LDAP_SUCCESS ); } @@ -2792,37 +2998,34 @@ int ldap_dn2str( LDAPDN *dn, char **str, 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: - + sv2l = strval2IA5strlen; + sv2s = strval2IA5str; + } + for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - - if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) { + if ( rdn2strlen( dn[ iRDN ], flags, &rdnl, sv2l ) ) { goto return_results; } len += rdnl; } - if ( ( *str = 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[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - if ( rdn2str( rdn, &( *str )[ l ], flags, + if ( rdn2str( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, sv2s ) ) { - LDAP_FREE( *str ); - *str = NULL; + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; goto return_results; } l += rdnl; @@ -2834,13 +3037,13 @@ got_funcs: * trim the last ',' (the allocated memory * is one byte longer than required) */ - ( *str )[ len - 1 ] = '\0'; + bv->bv_len = len - 1; + bv->bv_val[ bv->bv_len ] = '\0'; rc = LDAP_SUCCESS; break; case LDAP_DN_FORMAT_UFN: { - /* * FIXME: quoting from RFC 1781: * @@ -2882,15 +3085,14 @@ got_funcs: for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - 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; } @@ -2900,7 +3102,7 @@ got_funcs: #endif /* DC_IN_UFN */ } - if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) { + if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } @@ -2910,12 +3112,11 @@ got_funcs: #endif /* DC_IN_UFN */ for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t vl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - if ( rdn2UFNstr( rdn, &( *str )[ l ], + if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &vl ) ) { - LDAP_FREE( *str ); - *str = NULL; + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; goto return_results; } l += vl; @@ -2925,27 +3126,27 @@ got_funcs: * trim the last ', ' (the allocated memory * is two bytes longer than required) */ - ( *str )[ len - 2 ] = '\0'; + bv->bv_len = len - 2; + bv->bv_val[ bv->bv_len ] = '\0'; #ifdef DC_IN_UFN } else { last_iRDN = iRDN - 1; for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) { ber_len_t vl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - if ( rdn2UFNstr( rdn, &( *str )[ l ], + if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &vl ) ) { - LDAP_FREE( *str ); - *str = NULL; + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; goto return_results; } l += vl; } - if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) { - LDAP_FREE( *str ); - *str = NULL; + if ( !dn2domain( dn, bv, l, &last_iRDN ) ) { + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; goto return_results; } @@ -2954,35 +3155,31 @@ got_funcs: #endif /* DC_IN_UFN */ rc = LDAP_SUCCESS; - break; - } - case LDAP_DN_FORMAT_DCE: + } break; + case LDAP_DN_FORMAT_DCE: for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - - if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) { + if ( rdn2DCEstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; } - if ( ( *str = 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[ iRDN ][ 0 ]; - if ( rdn2DCEstr( rdn, &( *str )[ l ], flags, + if ( rdn2DCEstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, 0 ) ) { - LDAP_FREE( *str ); - *str = NULL; + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; goto return_results; } l += rdnl; @@ -2990,13 +3187,15 @@ got_funcs: assert( l == len ); - ( *str )[ len ] = '\0'; + bv->bv_len = len; + bv->bv_val[ bv->bv_len ] = '\0'; rc = LDAP_SUCCESS; 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, @@ -3013,30 +3212,33 @@ got_funcs: */ for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) { + if ( rdn2ADstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; } - if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) { + /* reserve room for trailing '/' in case the DN + * is exactly a domain */ + if ( ( bv->bv_val = LDAP_MALLOCX( len + 1 + 1, ctx ) ) == NULL ) + { rc = LDAP_NO_MEMORY; break; } iRDN--; - if ( iRDN && dn2domain( dn, *str, &iRDN ) ) { - for ( l = strlen( *str ); iRDN >= 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[ iRDN ][ 0 ]; + + trailing_slash = 0; - if ( rdn2ADstr( rdn, &( *str )[ l ], + if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, 0 ) ) { - LDAP_FREE( *str ); - *str = NULL; + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; goto return_results; } l += rdnl; @@ -3051,20 +3253,19 @@ got_funcs: * i.e. terminated by a domain component */ if ( flags & LDAP_DN_PEDANTIC ) { - LDAP_FREE( *str ); - *str = NULL; - rc = LDAP_INVALID_DN_SYNTAX; + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; + rc = LDAP_ENCODING_ERROR; break; } for ( l = 0; iRDN >= 0 ; iRDN-- ) { ber_len_t rdnl; - LDAPRDN *rdn = dn[ iRDN ][ 0 ]; - if ( rdn2ADstr( rdn, &( *str )[ l ], + if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, first ) ) { - LDAP_FREE( *str ); - *str = NULL; + LDAP_FREEX( bv->bv_val, ctx ); + bv->bv_val = NULL; goto return_results; } if ( first ) { @@ -3074,18 +3275,26 @@ got_funcs: } } - ( *str )[ len ] = '\0'; + if ( trailing_slash ) { + /* the DN is exactly a domain -- need a trailing + * slash; room was reserved in advance */ + 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; } - Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc ); + Debug( LDAP_DEBUG_ARGS, "<= ldap_dn2bv(%s)=%d %s\n", + bv->bv_val, rc, rc ? ldap_err2string( rc ) : "" ); + return_results:; return( rc ); }