X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fgetdn.c;h=781dca07afe6450849247111e1a12ed1e7caf525;hb=8c30114d847ff034dd9e9382d88e276fa7f82833;hp=e2104d8aef16a752956d7ffa5abf141105e0a8a7;hpb=c4164193adc35167ce1eb72c61f7432d3d6de509;p=openldap diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index e2104d8aef..781dca07af 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -25,10 +25,10 @@ /* 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, +static int str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, unsigned *retFlags ); static int DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags ); @@ -84,12 +84,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 ) { @@ -108,7 +111,11 @@ 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 ); @@ -127,7 +134,11 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes ) 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 ) { @@ -167,7 +178,11 @@ ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) 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 @@ -248,7 +263,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 +280,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 +296,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 ); @@ -305,7 +332,11 @@ ldap_dn_normalize( LDAP_CONST char *dnin, int rc; 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 ); @@ -384,10 +415,12 @@ ldap_dn_normalize( LDAP_CONST char *dnin, #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) \ @@ -587,22 +620,50 @@ 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( 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( &bv, dn, flags ); +} + +int +ldap_bv2dn( struct berval *bv, LDAPDN **dn, unsigned flags ) { const char *p; int rc = LDAP_DECODING_ERROR; int nrdns = 0; LDAPDN *newDN = NULL; - LDAPRDN *newRDN = NULL, *tmpDN[TMP_SLOTS]; + 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; @@ -623,10 +684,15 @@ ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags ) return LDAP_PARAM_ERROR; } - if ( str[ 0 ] == '\0' ) { + 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; if ( LDAP_DN_DCE( flags ) ) { @@ -638,7 +704,12 @@ ldap_str2dn( LDAP_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 @@ -647,12 +718,16 @@ ldap_str2dn( LDAP_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, (char **) &p, flags ); + err = ldap_bv2rdn( &tmpbv, &newRDN, (char **) &p, flags ); if ( err != LDAP_SUCCESS ) { goto parsing_error; } @@ -660,7 +735,7 @@ ldap_str2dn( LDAP_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 ] ) ) { @@ -690,22 +765,33 @@ ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags ) tmpDN[nrdns++] = newRDN; newRDN = NULL; -#if 0 /* - * prone to attacks? + * make the static RDN array dynamically rescalable */ - assert (nrdns < TMP_SLOTS); -#else - /* - * make the static AVA array dynamically rescalable - */ - if (nrdns >= TMP_SLOTS) { - rc = LDAP_DECODING_ERROR; - goto parsing_error; + if ( nrdns == num_slots ) { + LDAPRDN **tmp; + + if ( tmpDN == tmpDN_ ) { + tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPRDN * ) ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) ); + + } else { + tmp = LDAP_REALLOC( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ) ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + } + + tmpDN = tmp; + num_slots *= 2; } -#endif - if ( p[ 0 ] == '\0' ) { + if ( p >= end || p[ 0 ] == '\0' ) { /* * the DN is over, phew */ @@ -739,11 +825,22 @@ parsing_error:; ldap_rdnfree( newRDN ); } - for (nrdns-- ;nrdns>=0; nrdns-- ) + for ( nrdns-- ;nrdns >= 0; nrdns-- ) { ldap_rdnfree( tmpDN[nrdns] ); + } return_result:; - Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc ); + + if ( tmpDN != tmpDN_ ) { + LDAP_FREE( tmpDN ); + } + +#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 ); @@ -761,7 +858,22 @@ int ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn, char **n_in, unsigned flags ) { - const char **n = (const char **) n_in; + 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( &bv, rdn, n_in, flags ); +} + +int +ldap_bv2rdn( struct berval *bv, LDAPRDN **rdn, + char **n_in, unsigned flags ) +{ + const char **n = (const char **) n_in; const char *p; int navas = 0; int state = B4AVA; @@ -773,13 +885,20 @@ ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn, struct berval attrValue = { 0, NULL }; LDAPRDN *newRDN = NULL; - LDAPAVA *tmpRDN[TMP_SLOTS]; + 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; @@ -803,8 +922,14 @@ ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn, return LDAP_PARAM_ERROR; } - if ( str[ 0 ] == '\0' ) { + 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; @@ -1073,7 +1198,8 @@ ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn, switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV3: - if ( str2strval( p, &attrValue, &p, flags, + if ( str2strval( p, stoplen - ( p - str ), + &attrValue, &p, flags, &attrValueEncoding ) ) { goto parsing_error; } @@ -1132,7 +1258,31 @@ ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn, attrValue.bv_val = NULL; attrValue.bv_len = 0; - assert(navas < TMP_SLOTS); + /* + * prepare room for new AVAs if needed + */ + if (navas == num_slots) { + LDAPAVA **tmp; + + if ( tmpRDN == tmpRDN_ ) { + tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPAVA * ) ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) ); + + } else { + tmp = LDAP_REALLOC( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ) ); + if ( tmp == NULL ) { + rc = LDAP_NO_MEMORY; + goto parsing_error; + } + } + + tmpRDN = tmp; + num_slots *= 2; + } } /* @@ -1205,13 +1355,16 @@ parsing_error:; free( attrValue.bv_val ); } - for (navas-- ; navas>=0; navas-- ) + for ( navas-- ; navas >= 0; navas-- ) { ldap_avafree( tmpRDN[navas] ); + } return_result:; - Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n", - p - str, str, rc ); + if ( tmpRDN != tmpRDN_ ) { + LDAP_FREE( tmpRDN ); + } + if ( rdn ) { *rdn = newRDN; } @@ -1225,9 +1378,9 @@ 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, unsigned *retFlags ) { - const char *p, *startPos, *endPos = NULL; + const char *p, *end, *startPos, *endPos = NULL; ber_len_t len, escapes; assert( str ); @@ -1235,16 +1388,14 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla assert( next ); *next = NULL; - - for ( startPos = p = str, escapes = 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; } @@ -1255,11 +1406,6 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla hexstr2bin( p, &c ); escapes += 2; - if ( c == 0 ) { - /* do not accept zero, right? */ - return( 1 ); - } - if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) { /* @@ -1284,6 +1430,9 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla 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 ] ) ) @@ -1331,7 +1480,13 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla val->bv_len = len; if ( escapes == 0 ) { - val->bv_val = LDAP_STRNDUP( startPos, len ); + if ( *retFlags == LDAP_AVA_NONPRINTABLE ) { + val->bv_val = LDAP_MALLOC( len + 1 ); + AC_MEMCPY( val->bv_val, startPos, len ); + val->bv_val[ len ] = '\0'; + } else { + val->bv_val = LDAP_STRNDUP( startPos, len ); + } } else { ber_len_t s, d; @@ -1340,9 +1495,7 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla 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++ ]; @@ -1364,7 +1517,7 @@ 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 ); @@ -1598,7 +1751,7 @@ 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 ); @@ -1834,8 +1987,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 ); @@ -1844,7 +2007,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 ); } } @@ -1854,7 +2017,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 @@ -1903,7 +2070,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 @@ -1911,7 +2097,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 ] ) ) @@ -2686,7 +2876,7 @@ ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags ) break; default: - return( LDAP_PARAM_ERROR ); + return LDAP_PARAM_ERROR; } bv->bv_val = LDAP_MALLOC( l + 1 ); @@ -2772,11 +2962,15 @@ 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 @@ -2791,13 +2985,13 @@ 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: - + sv2l = strval2IA5strlen; + sv2s = strval2IA5str; + } + for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { ber_len_t rdnl; LDAPRDN *rdn = dn[ 0 ][ iRDN ]; @@ -2840,7 +3034,6 @@ got_funcs: break; case LDAP_DN_FORMAT_UFN: { - /* * FIXME: quoting from RFC 1781: * @@ -2955,11 +3148,10 @@ 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[ 0 ][ iRDN ]; iRDN++ ) { ber_len_t rdnl; LDAPRDN *rdn = dn[ 0 ][ iRDN ]; @@ -2998,7 +3190,6 @@ got_funcs: break; case LDAP_DN_FORMAT_AD_CANONICAL: { - /* * Sort of UFN for DCE DNs: a slash ('/') separated * global->local DN with no types; strictly speaking, @@ -3080,16 +3271,210 @@ got_funcs: bv->bv_val[ bv->bv_len ] = '\0'; rc = LDAP_SUCCESS; - break; - } + } break; default: 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(LDAPDN) + sizeof(LDAPRDN *) * (nrdns+1); + dnsize += sizeof(LDAPRDN) * nrdns + 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[0] = (LDAPRDN**)(newDN+1); + newDN[0][nrdns] = NULL; + newRDN = (LDAPRDN*)(newDN[0] + nrdns+1); + newAVA = (LDAPAVA*)(newRDN + navas + nrdns*2); + 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[0][k] = NULL; + newRDN = (LDAPRDN*)(newRDN[0]+k+1); + } + newDN[0][j++] = newRDN; + + newRDN[0] = (LDAPAVA**)(newRDN+1); + 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 ); + } else { +get_oid: newAVA->la_attr.bv_val = oidptr; + newAVA->la_attr.bv_len = OBJ_obj2txt( oidptr, oidrem, obj, 1 ); + 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 = 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 ); + 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 */ + ber_dupbv( &newAVA->la_value, &Val ); + default: + ; + } + newRDN[0][k] = newAVA; + newAVA++; + k++; + } + newRDN[0][k] = NULL; + + if ( func ) { + rc = func( newDN, flags ); + if ( rc != LDAP_SUCCESS ) + goto nomem; + } + + rc = ldap_dn2bv( newDN, bv, LDAP_DN_FORMAT_LDAPV3 ); + +nomem: + for (;baseAVA < newAVA; baseAVA++) { + 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 */ +