]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/getdn.c
Fix ITS#1843, don't deref NULL string in ldap_pvt_str2upper
[openldap] / libraries / libldap / getdn.c
index ecd30d4c0ddf1eaf43134036d33e8584bc3d365c..4dd2279ee5fd0ab31748b52fb4eca7e39aa5c5cf 100644 (file)
@@ -1,6 +1,6 @@
 /* $OpenLDAP$ */
 /*
 /* $OpenLDAP$ */
 /*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 /*  Portions
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 /*  Portions
 #include <stdio.h>
 
 #include <ac/stdlib.h>
 #include <stdio.h>
 
 #include <ac/stdlib.h>
-
-#include <ac/ctype.h>
 #include <ac/socket.h>
 #include <ac/string.h>
 #include <ac/time.h>
 
 #include "ldap-int.h"
 #include <ac/socket.h>
 #include <ac/string.h>
 #include <ac/time.h>
 
 #include "ldap-int.h"
+#include "ldap_schema.h"
 
 
-/* forces the use of new dn parsing routines */
-/* #define USE_LDAP_DN_PARSING */
 /* 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
 /* 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 char *dn2dn( const char *dnin, unsigned fin, unsigned fout );
-
-/* from libraries/libldap/schema.c */
-extern char * parse_numericoid(const char **sp, int *code, const int flags);
+#define PRETTY_ESCAPE
 
 /* parsing/printing routines */
 
 /* 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 );
                const char **next, unsigned flags, unsigned *retFlags );
-static int DCE2strval( const char *str, struct berval **val, 
+static int DCE2strval( const char *str, struct berval *val, 
                const char **next, unsigned flags );
                const char **next, unsigned flags );
-static int IA52strval( const char *str, struct berval **val, 
+static int IA52strval( const char *str, struct berval *val, 
                const char **next, unsigned flags );
                const char **next, unsigned flags );
-static int quotedIA52strval( const char *str, struct berval **val, 
+static int quotedIA52strval( const char *str, struct berval *val, 
                const char **next, unsigned flags );
                const char **next, unsigned flags );
-static int hexstr2binval( const char *str, struct berval **val, 
+static int hexstr2binval( const char *str, struct berval *val, 
                const char **next, unsigned flags );
 static int hexstr2bin( const char *str, char *c );
 static int byte2hexpair( const char *val, char *pair );
                const char **next, unsigned flags );
 static int hexstr2bin( const char *str, char *c );
 static int byte2hexpair( const char *val, char *pair );
@@ -64,38 +57,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 );
                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 */
 
 /* AVA helpers */
-LDAPAVA * ldapava_new( const struct berval *attr, const struct berval *val, 
-               unsigned flags );
-void ldapava_free( LDAPAVA *ava );
-LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
-LDAPRDN * ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
-/* void ldapava_free_rdn( LDAPRDN *rdn ); in ldap.h */
-LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
-LDAPDN * ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where );
-/* void ldapava_free_dn( LDAPDN *dn ); in ldap.h */
+static LDAPAVA * ldapava_new(
+       const struct berval *attr, const struct berval *val, unsigned flags );
 
 /* Higher level helpers */
 
 /* Higher level helpers */
-static int rdn2strlen( LDAPRDN *rdn, ber_len_t *len,
+static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
                int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
                int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
-static int rdn2str( LDAPRDN *rdn, char *str, 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 * ));
                int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
-static int rdn2UFNstrlen( LDAPRDN *rdn, ber_len_t *len  );
-static int rdn2UFNstr( LDAPRDN *rdn, char *str, ber_len_t *len );
-static int rdn2DCEstrlen( LDAPRDN *rdn, ber_len_t *len );
-static int rdn2DCEstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first );
-static int rdn2ADstrlen( LDAPRDN *rdn, ber_len_t *len );
-static int rdn2ADstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first );
-       
-#ifndef USE_LDAP_DN_PARSING    /* deprecated */
-#define NAME_TYPE_LDAP_RDN     0
-#define NAME_TYPE_LDAP_DN      1
-#define NAME_TYPE_DCE_DN       2
-
-static char **explode_name( const char *name, int notypes, int is_type );
-#endif /* !USE_LDAP_DN_PARSING */
+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
 
 /*
  * RFC 1823 ldap_get_dn
@@ -106,12 +84,15 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry )
        char            *dn;
        BerElement      tmp;
 
        char            *dn;
        BerElement      tmp;
 
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_get_dn\n" ));
+#else
        Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
        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 ) {
 
        tmp = *entry->lm_ber;   /* struct copy */
        if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
@@ -128,47 +109,18 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry )
 char *
 ldap_dn2ufn( LDAP_CONST char *dn )
 {
 char *
 ldap_dn2ufn( LDAP_CONST char *dn )
 {
-#ifndef USE_LDAP_DN_PARSING    /* deprecated */
-       char    *ufn;
-       char    **vals;
-       int i;
+       char    *out = NULL;
 
 
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn2ufn\n" ));
+#else
        Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
        Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
+#endif
 
 
-       /* produces completely untyped UFNs */
-
-       if( dn == NULL ) {
-               return NULL;
-       }
-
-       vals = ldap_explode_dn( dn , 0 );
-       if( vals == NULL ) {
-               return NULL;
-       }
-
-       for ( i = 0; vals[i]; i++ ) {
-               char **rvals;
-
-               rvals = ldap_explode_rdn( vals[i] , 1 );
-               if ( rvals == NULL ) {
-                       LDAP_VFREE( vals );
-                       return NULL;
-               }
-
-               LDAP_FREE( vals[i] );
-               vals[i] = ldap_charray2str( rvals, " + " );
-               LDAP_VFREE( rvals );
-       }
-
-       ufn = ldap_charray2str( vals, ", " );
-
-       LDAP_VFREE( vals );
-       return ufn;
-#else /* USE_LDAP_DN_PARSING */
-       Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
-
-       return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_UFN );
-#endif /* USE_LDAP_DN_PARSING */
+       ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
+               &out, LDAP_DN_FORMAT_UFN );
+       
+       return( out );
 }
 
 /*
 }
 
 /*
@@ -177,96 +129,101 @@ ldap_dn2ufn( LDAP_CONST char *dn )
 char **
 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
 {
 char **
 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
 {
-#ifndef USE_LDAP_DN_PARSING    /* deprecated */
-       Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
-
-       return explode_name( dn, notypes, NAME_TYPE_LDAP_DN );
-#else /* USE_LDAP_DN_PARSING */
        LDAPDN  *tmpDN;
        char    **values = NULL;
        int     iRDN;
        unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
        
        LDAPDN  *tmpDN;
        char    **values = NULL;
        int     iRDN;
        unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
        
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_explode_dn\n" ));
+#else
        Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
        Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
+#endif
 
 
-       if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 ) 
+       if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) 
                        != LDAP_SUCCESS ) {
                        != LDAP_SUCCESS ) {
-               return( NULL );
+               return NULL;
        }
 
        }
 
-       for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
-               char    *str, **v = NULL;
-               
-               ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
+       if( tmpDN == NULL ) {
+               values = LDAP_MALLOC( sizeof( char * ) );
+               if( values == NULL ) return NULL;
 
 
-               v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
-               if ( v == NULL ) {
-                       LBER_VFREE( values );
-                       ldapava_free_dn( tmpDN );
-                       return( NULL );
-               }
-               values = v;
-               values[ iRDN ] = str;
+               values[0] = NULL;
+               return values;
+       }
+
+       for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ );
+
+       values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
+       if ( values == NULL ) {
+               ldap_dnfree( tmpDN );
+               return NULL;
+       }
+
+       for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ ) {
+               ldap_rdn2str( tmpDN[ 0 ][ iRDN ], &values[ iRDN ], flag );
        }
        }
+       ldap_dnfree( tmpDN );
        values[ iRDN ] = NULL;
 
        values[ iRDN ] = NULL;
 
-       return( values );
-#endif /* USE_LDAP_DN_PARSING */
+       return values;
 }
 
 char **
 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
 {
 }
 
 char **
 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
 {
-#ifndef USE_LDAP_DN_PARSING    /* deprecated */
-       Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
-
-       return explode_name( rdn, notypes, NAME_TYPE_LDAP_RDN );
-#else /* USE_LDAP_DN_PARSING */
-       LDAPDN  *tmpDN;
-       char    **values = NULL;
-       int     iAVA;
-       unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
+       LDAPRDN         *tmpRDN;
+       char            **values = NULL;
+       const char      *p;
+       int             iAVA;
        
        
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_explode_rdn\n" ));
+#else
        Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
        Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
+#endif
 
        /*
 
        /*
-        * we assume this dn is made of one rdn only
+        * we only parse the first rdn
+        * FIXME: we prefer efficiency over checking if the _ENTIRE_
+        * dn can be parsed
         */
         */
-       if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 ) 
+       if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP ) 
                        != LDAP_SUCCESS ) {
                return( NULL );
        }
 
                        != LDAP_SUCCESS ) {
                return( NULL );
        }
 
-       for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
+       for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) ;
+       values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
+       if ( values == NULL ) {
+               ldap_rdnfree( tmpRDN );
+               return( NULL );
+       }
+
+       for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) {
                ber_len_t       l = 0, vl, al = 0;
                ber_len_t       l = 0, vl, al = 0;
-               char            *str, **v = NULL;
-               LDAPAVA         *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
-               
-               v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
-               if ( v == NULL ) {
-                       goto error_return;
-               }
-               values = v;
+               char            *str;
+               LDAPAVA         *ava = tmpRDN[ 0 ][ iAVA ];
                
                if ( ava->la_flags == LDAP_AVA_BINARY ) {
                
                if ( ava->la_flags == LDAP_AVA_BINARY ) {
-                       vl = 1 + 2 * ava->la_value->bv_len;
+                       vl = 1 + 2 * ava->la_value.bv_len;
 
                } else {
 
                } else {
-                       int rc;
-                       
-                       if ( strval2strlen( ava->la_value, 
+                       if ( strval2strlen( &ava->la_value, 
                                                ava->la_flags, &vl ) ) {
                                goto error_return;
                        }
                }
                
                if ( !notypes ) {
                                                ava->la_flags, &vl ) ) {
                                goto error_return;
                        }
                }
                
                if ( !notypes ) {
-                       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 );
 
                        str = LDAP_MALLOC( l + 1 );
-                       AC_MEMCPY( str, ava->la_attr->bv_val, 
-                                       ava->la_attr->bv_len );
-                       str[ ava->la_attr->bv_len + 1 ] = '=';
+                       AC_MEMCPY( str, ava->la_attr.bv_val, 
+                                       ava->la_attr.bv_len );
+                       str[ al++ ] = '=';
 
                } else {
                        l = vl;
 
                } else {
                        l = vl;
@@ -275,12 +232,12 @@ ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
                
                if ( ava->la_flags == LDAP_AVA_BINARY ) {
                        str[ al++ ] = '#';
                
                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 {
                                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;
                        }
                                        ava->la_flags, &vl ) ) {
                                goto error_return;
                        }
@@ -291,294 +248,120 @@ ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
        }
        values[ iAVA ] = NULL;
 
        }
        values[ iAVA ] = NULL;
 
-       ldapava_free_dn( tmpDN );
+       ldap_rdnfree( tmpRDN );
 
        return( values );
 
 
        return( values );
 
-error_return:
+error_return:;
        LBER_VFREE( values );
        LBER_VFREE( values );
-       ldapava_free_dn( tmpDN );
+       ldap_rdnfree( tmpRDN );
        return( NULL );
        return( NULL );
-#endif /* USE_LDAP_DN_PARSING */
 }
 
 char *
 ldap_dn2dcedn( LDAP_CONST char *dn )
 {
 }
 
 char *
 ldap_dn2dcedn( LDAP_CONST char *dn )
 {
-#ifndef USE_LDAP_DN_PARSING    /* deprecated */
-       char *dce, *q, **rdns, **p;
-       int len = 0;
+       char    *out = NULL;
 
 
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn2dcedn\n" ));
+#else
        Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
        Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
+#endif
 
 
-       rdns = explode_name( dn, 0, NAME_TYPE_LDAP_DN );
-       if ( rdns == NULL ) {
-               return NULL;
-       }
-       
-       for ( p = rdns; *p != NULL; p++ ) {
-               len += strlen( *p ) + 1;
-       }
-
-       q = dce = LDAP_MALLOC( len + 1 );
-       if ( dce == NULL ) {
-               return NULL;
-       }
-
-       p--; /* get back past NULL */
-
-       for ( ; p != rdns; p-- ) {
-               strcpy( q, "/" );
-               q++;
-               strcpy( q, *p );
-               q += strlen( *p );
-       }
-
-       strcpy( q, "/" );
-       q++;
-       strcpy( q, *p );
-       
-       return dce;
-#else /* USE_LDAP_DN_PARSING */
-       Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
+       ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
+                                  &out, LDAP_DN_FORMAT_DCE );
 
 
-       return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_DCE );
-#endif /* USE_LDAP_DN_PARSING */
+       return( out );
 }
 
 char *
 ldap_dcedn2dn( LDAP_CONST char *dce )
 {
 }
 
 char *
 ldap_dcedn2dn( LDAP_CONST char *dce )
 {
-#ifndef USE_LDAP_DN_PARSING
-       char *dn, *q, **rdns, **p;
-       int len;
+       char    *out = NULL;
 
 
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dcedn2dn\n" ));
+#else
        Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
        Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
+#endif
 
 
-       rdns = explode_name( dce, 0, NAME_TYPE_DCE_DN );
-       if ( rdns == NULL ) {
-               return NULL;
-       }
-
-       len = 0;
-
-       for ( p = rdns; *p != NULL; p++ ) {
-               len += strlen( *p ) + 1;
-       }
-
-       q = dn = LDAP_MALLOC( len );
-       if ( dn == NULL ) {
-               return NULL;
-       }
-
-       p--;
-
-       for ( ; p != rdns; p-- ) {
-               strcpy( q, *p );
-               q += strlen( *p );
-               strcpy( q, "," );
-               q++;
-       }
+       ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
 
 
-       if ( *dce == '/' ) {
-               /* the name was fully qualified, thus the most-significant
-                * RDN was empty. trash the last comma */
-               q--;
-               *q = '\0';
-       } else {
-               /* the name was relative. copy the most significant RDN */
-               strcpy( q, *p );
-       }
-
-       return dn;
-#else /* USE_LDAP_DN_PARSING */
-       Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
-
-       return dn2dn( dce, LDAP_DN_FORMAT_DCE, LDAP_DN_FORMAT_LDAPV3 );
-#endif /* USE_LDAP_DN_PARSING */
+       return( out );
 }
 
 char *
 ldap_dn2ad_canonical( LDAP_CONST char *dn )
 {
 }
 
 char *
 ldap_dn2ad_canonical( LDAP_CONST char *dn )
 {
-       Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
-
-       return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_AD_CANONICAL );
-}
-
-#ifndef USE_LDAP_DN_PARSING    /* deprecated */
-#define INQUOTE                1
-#define OUTQUOTE       2
-
-static char **
-explode_name( const char *name, int notypes, int is_type )
-{
-       const char *p, *q, *rdn;
-       char **parts = NULL;
-       int     offset, state, have_equals, count = 0, endquote, len;
-
-       /* safe guard */
-       if(name == NULL) name = "";
+       char    *out = NULL;
 
 
-       /* skip leading whitespace */
-       while( ldap_utf8_isspace( name )) {
-               LDAP_UTF8_INCR( name );
-       }
-
-       p = rdn = name;
-       offset = 0;
-       state = OUTQUOTE;
-       have_equals=0;
-
-       do {
-               /* step forward */
-               p += offset;
-               offset = 1;
-
-               switch ( *p ) {
-               case '\\':
-                       if ( p[1] != '\0' ) {
-                               offset = LDAP_UTF8_OFFSET(++p);
-                       }
-                       break;
-               case '"':
-                       if ( state == INQUOTE )
-                               state = OUTQUOTE;
-                       else
-                               state = INQUOTE;
-                       break;
-               case '=':
-                       if( state == OUTQUOTE ) have_equals++;
-                       break;
-               case '+':
-                       if (is_type == NAME_TYPE_LDAP_RDN)
-                               goto end_part;
-                       break;
-               case '/':
-                       if (is_type == NAME_TYPE_DCE_DN)
-                               goto end_part;
-                       break;
-               case ';':
-               case ',':
-                       if (is_type == NAME_TYPE_LDAP_DN)
-                               goto end_part;
-                       break;
-               case '\0':
-               end_part:
-                       if ( state == OUTQUOTE ) {
-                               ++count;
-                               have_equals=0;
-
-                               if ( parts == NULL ) {
-                                       if (( parts = (char **)LDAP_MALLOC( 8
-                                                * sizeof( char *))) == NULL )
-                                               return( NULL );
-                               } else if ( count >= 8 ) {
-                                       if (( parts = (char **)LDAP_REALLOC( parts,
-                                               (count+1) * sizeof( char *)))
-                                               == NULL )
-                                               return( NULL );
-                               }
-
-                               parts[ count ] = NULL;
-                               endquote = 0;
-
-                               if ( notypes ) {
-                                       for ( q = rdn; q < p && *q != '='; ++q ) {
-                                               /* EMPTY */;
-                                       }
-
-                                       if ( q < p ) {
-                                               rdn = ++q;
-                                       }
-
-                                       if ( *rdn == '"' ) {
-                                               ++rdn;
-                                       }
-                                       
-                                       if ( p[-1] == '"' ) {
-                                               endquote = 1;
-                                               --p;
-                                       }
-                               }
-
-                               len = p - rdn;
-
-                               if (( parts[ count-1 ] = (char *)LDAP_CALLOC( 1,
-                                   len + 1 )) != NULL )
-                               {
-                                       AC_MEMCPY( parts[ count-1 ], rdn, len );
-
-                                       if( !endquote ) {
-                                               /* skip trailing spaces */
-                                               while( len > 0 && ldap_utf8_isspace(
-                                                       &parts[count-1][len-1] ) )
-                                               {
-                                                       --len;
-                                               }
-                                       }
-
-                                       parts[ count-1 ][ len ] = '\0';
-                               }
-
-                               /*
-                                *  Don't forget to increment 'p' back to where
-                                *  it should be.  If we don't, then we will
-                                *  never get past an "end quote."
-                                */
-                               if ( endquote == 1 )
-                                       p++;
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn2ad_canonical\n" ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
+#endif
 
 
-                               rdn = *p ? &p[1] : p;
-                               while ( ldap_utf8_isspace( rdn ) )
-                                       ++rdn;
-                       } break;
-               }
-       } while ( *p );
+       ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
+                      &out, LDAP_DN_FORMAT_AD_CANONICAL );
 
 
-       return( parts );
+       return( out );
 }
 }
-#endif /* !USE_LDAP_DN_PARSING */
 
 /*
 
 /*
- * 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:
  * 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_DCE              (?)
  *
  *     LDAP_DN_FORMAT_LDAPV3           (rfc 2253 and ldapbis)
  *     LDAP_DN_FORMAT_LDAPV2           (rfc 1779)
  *     LDAP_DN_FORMAT_DCE              (?)
  *
- * fout can be any of the above plus:
+ * 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_AD_CANONICAL     (?)
  */
  *     LDAP_DN_FORMAT_UFN              (rfc 1781, partial and with extensions)
  *     LDAP_DN_FORMAT_AD_CANONICAL     (?)
  */
-static char *
-dn2dn( const char *dnin, unsigned fin, unsigned fout )
+int
+ldap_dn_normalize( LDAP_CONST char *dnin,
+       unsigned fin, char **dnout, unsigned fout )
 {
 {
-       char    *dnout = NULL;
+       int     rc;
        LDAPDN  *tmpDN = NULL;
 
        LDAPDN  *tmpDN = NULL;
 
-       if( dnin == NULL ) {
-               return NULL;
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn_normalize\n" ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
+#endif
+
+       assert( dnout );
+
+       *dnout = NULL;
+
+       if ( dnin == NULL ) {
+               return( LDAP_SUCCESS );
        }
 
        }
 
-       if ( ldap_str2dn( dnin , &tmpDN, fin ) != LDAP_SUCCESS ) {
-               return NULL;
+       rc = ldap_str2dn( dnin , &tmpDN, fin );
+       if ( rc != LDAP_SUCCESS ) {
+               return( rc );
        }
 
        }
 
-       /* don't care about the result ... */
-       ldap_dn2str( tmpDN, &dnout, fout );
+       rc = ldap_dn2str( tmpDN, dnout, fout );
 
 
-       ldapava_free_dn( tmpDN );
+       ldap_dnfree( tmpDN );
 
 
-       return dnout;
+       return( rc );
 }
 
 /* States */
 #define B4AVA                  0x0000
 
 }
 
 /* States */
 #define B4AVA                  0x0000
 
-#define        B4ATTRTYPE              0x0001
+/* #define     B4ATTRTYPE              0x0001 */
 #define B4OIDATTRTYPE          0x0002
 #define B4STRINGATTRTYPE       0x0003
 
 #define B4OIDATTRTYPE          0x0002
 #define B4STRINGATTRTYPE       0x0003
 
@@ -593,28 +376,28 @@ dn2dn( const char *dnin, unsigned fin, unsigned fout )
 #define B4IA5VALUE             0x0040
 #define B4BINARYVALUE          0x0050
 
 #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_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_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) )
 #define LDAP_DN_LANG_SEP(c)            ( (c) == ';' )
 #define LDAP_DN_ATTRDESC_CHAR(c) \
        ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
@@ -632,12 +415,19 @@ dn2dn( const char *dnin, unsigned fin, unsigned fout )
 #define LDAP_DN_NE(c) \
        ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
          || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
 #define LDAP_DN_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(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_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) || 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 */
 #define        LDAP_DN_VALUE_END_V2(c) \
 
 /* LDAPv2 */
 #define        LDAP_DN_VALUE_END_V2(c) \
@@ -691,24 +481,33 @@ dn2dn( const char *dnin, unsigned fin, unsigned fout )
 /* generics */
 #define LDAP_DN_HEXPAIR(s) \
        ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
 /* 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? */
 /* 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? */
-#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: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
+/* 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][0] && !(r)[0][1] \
+         && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
+         && ((r)[0][0]->la_attr.bv_len == 2) \
+         && (((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
+               || ((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
+         && (((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
+               || ((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
 
 /* Composite rules */
 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
 
 /* Composite rules */
 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
-       ( ( (f) & LDAP_DN_FORMAT_LDAPV2 ) \
+       ( LDAP_DN_LDAPV2(f) \
          || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
 #define LDAP_DN_ALLOW_SPACES(f) \
          || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
 #define LDAP_DN_ALLOW_SPACES(f) \
-       ( ( (f) & LDAP_DN_FORMAT_LDAPV2 ) \
+       ( LDAP_DN_LDAPV2(f) \
          || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
          || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
+#define LDAP_DN_LDAP(f) \
+       ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
 #define LDAP_DN_LDAPV3(f) \
        ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
 #define LDAP_DN_LDAPV2(f) \
 #define LDAP_DN_LDAPV3(f) \
        ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
 #define LDAP_DN_LDAPV2(f) \
@@ -734,86 +533,49 @@ ldapava_new( const struct berval *attr, const struct berval *val,
        assert( attr );
        assert( val );
 
        assert( attr );
        assert( val );
 
-       ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
+       ava = LDAP_MALLOC( sizeof( LDAPAVA ) + attr->bv_len + 1 );
        
        /* should we test it? */
        if ( ava == NULL ) {
                return( NULL );
        }
 
        
        /* should we test it? */
        if ( ava == NULL ) {
                return( NULL );
        }
 
-       ava->la_attr = ( struct berval * )attr;
-       ava->la_value = ( struct berval * )val;
+       ava->la_attr.bv_len = attr->bv_len;
+       ava->la_attr.bv_val = (char *)(ava+1);
+       AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len );
+       ava->la_attr.bv_val[attr->bv_len] = '\0';
+
+       ava->la_value = *val;
        ava->la_flags = flags;
 
        ava->la_flags = flags;
 
+       ava->la_private = NULL;
+
        return( ava );
 }
 
 void
        return( ava );
 }
 
 void
-ldapava_free( LDAPAVA *ava )
+ldap_avafree( LDAPAVA *ava )
 {
        assert( ava );
 
 {
        assert( ava );
 
-       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;
+#if 0
+       /* ava's private must be freed by caller
+        * (at present let's skip this check because la_private
+        * basically holds static data) */
+       assert( ava->la_private == NULL );
+#endif
 
 
-       assert( ava );
+#if 0
+       /* la_attr is now contiguous with ava, not freed separately */
+       LDAP_FREE( ava->la_attr.bv_val );
+#endif
+       LDAP_FREE( ava->la_value.bv_val );
 
 
-       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;
-
-       return( newRDN );
-}
-
-LDAPRDN *
-ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
-{
-       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_FREE( ava );
 }
 
 void
 }
 
 void
-ldapava_free_rdn( LDAPRDN *rdn )
+ldap_rdnfree( LDAPRDN *rdn )
 {
        int iAVA;
        
 {
        int iAVA;
        
@@ -821,70 +583,15 @@ ldapava_free_rdn( LDAPRDN *rdn )
                return;
        }
 
                return;
        }
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               assert( rdn[ iAVA ][ 0 ] );
-
-               ldapava_free( rdn[ iAVA ][ 0 ] );
-       }
-
-       LDAP_VFREE( rdn );
-}
-
-LDAPDN *
-ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
-{
-       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 */
-               }
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               ldap_avafree( rdn[ 0 ][ iAVA ] );
        }
        }
-       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_FREE( rdn );
 }
 
 void
 }
 
 void
-ldapava_free_dn( LDAPDN *dn )
+ldap_dnfree( LDAPDN *dn )
 {
        int iRDN;
        
 {
        int iRDN;
        
@@ -892,18 +599,16 @@ ldapava_free_dn( LDAPDN *dn )
                return;
        }
 
                return;
        }
 
-       for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
-               assert( dn[ iRDN ][ 0 ] );
-
-               ldapava_free_rdn( dn[ iRDN ][ 0 ] );
+       for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
+               ldap_rdnfree( dn[ 0 ][ iRDN ] );
        }
 
        }
 
-       LDAP_VFREE( dn );
+       LDAP_FREE( dn );
 }
 
 /*
  * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
 }
 
 /*
  * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
- * into a structured representation of the DN, by separating attribute
+ * into a structural representation of the DN, by separating attribute
  * types and values encoded in the more appropriate form, which is
  * string or OID for attribute types and binary form of the BER encoded
  * value or Unicode string. Formats different from LDAPv3 are parsed
  * types and values encoded in the more appropriate form, which is
  * string or OID for attribute types and binary form of the BER encoded
  * value or Unicode string. Formats different from LDAPv3 are parsed
@@ -915,23 +620,56 @@ ldapava_free_dn( LDAPDN *dn )
  * and readable as soon as it works as expected.
  */
 
  * 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( 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
 int
-ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
+ldap_bv2dn( struct berval *bv, LDAPDN **dn, unsigned flags )
 {
        const char      *p;
 {
        const char      *p;
-       int             rc = LDAP_INVALID_DN_SYNTAX;
+       int             rc = LDAP_DECODING_ERROR;
+       int             nrdns = 0;
 
        LDAPDN          *newDN = NULL;
 
        LDAPDN          *newDN = NULL;
-       LDAPRDN         *newRDN = NULL;
+       LDAPRDN         *newRDN = NULL, *tmpDN_[TMP_RDN_SLOTS], **tmpDN = tmpDN_;
+       int             num_slots = TMP_RDN_SLOTS;
+       char            *str = bv->bv_val;
+       char            *end = str + bv->bv_len;
        
        
-       assert( str );
+       assert( bv );
+       assert( bv->bv_val );
        assert( dn );
 
        assert( dn );
 
-       Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_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;
 
        switch ( LDAP_DN_FORMAT( flags ) ) {
 
        *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:
        case LDAP_DN_FORMAT_LDAPV3:
        case LDAP_DN_FORMAT_LDAPV2:
        case LDAP_DN_FORMAT_DCE:
@@ -940,14 +678,20 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
        /* unsupported in str2dn */
        case LDAP_DN_FORMAT_UFN:
        case LDAP_DN_FORMAT_AD_CANONICAL:
        /* 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:
        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;
        }
 
        p = str;
@@ -961,32 +705,57 @@ ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
                        goto parsing_error;
                }
                p++;
                        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
+                */
+               if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
+                       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;
                
                
-               rc = ldap_str2rdn( p, &newRDN, &p, flags );
-               if ( rc != LDAP_SUCCESS ) {
+               err = ldap_bv2rdn( &tmpbv, &newRDN, (char **) &p, flags );
+               if ( err != LDAP_SUCCESS ) {
                        goto parsing_error;
                }
 
                /* 
                 * We expect a rdn separator
                 */
                        goto parsing_error;
                }
 
                /* 
                 * We expect a rdn separator
                 */
-               if ( p[ 0 ] ) {
+               if ( p < end && p[ 0 ] ) {
                        switch ( LDAP_DN_FORMAT( flags ) ) {
                        case LDAP_DN_FORMAT_LDAPV3:
                        switch ( LDAP_DN_FORMAT( flags ) ) {
                        case LDAP_DN_FORMAT_LDAPV3:
-                       case LDAP_DN_FORMAT_LDAPV2:
                                if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
                                if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
-                                       rc = LDAP_OTHER;
+                                       rc = LDAP_DECODING_ERROR;
+                                       goto parsing_error;
+                               }
+                               break;
+       
+                       case LDAP_DN_FORMAT_LDAP:
+                       case LDAP_DN_FORMAT_LDAPV2:
+                               if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
+                                       rc = LDAP_DECODING_ERROR;
                                        goto parsing_error;
                                }
                                break;
        
                        case LDAP_DN_FORMAT_DCE:
                                if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
                                        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;
                                        goto parsing_error;
                                }
                                break;
@@ -994,44 +763,85 @@ 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_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;
+               }
                                
                                
-               if ( p[ 0 ] == '\0' ) {
-                                       
+               if ( p >= end || p[ 0 ] == '\0' ) {
                        /* 
                         * the DN is over, phew
                         */
                        /* 
                         * the DN is over, phew
                         */
-                       rc = LDAP_SUCCESS;
+                       newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) +
+                               sizeof(LDAPRDN *) * (nrdns+1));
+                       if ( newDN == NULL ) {
+                               rc = LDAP_NO_MEMORY;
+                               goto parsing_error;
+                       } else {
+                               int i;
+
+                               newDN[0] = (LDAPRDN **)(newDN+1);
+
+                               if ( LDAP_DN_DCE( flags ) ) {
+                                       /* add in reversed order */
+                                       for ( i=0; i<nrdns; i++ )
+                                               newDN[0][i] = tmpDN[nrdns-1-i];
+                               } else {
+                                       for ( i=0; i<nrdns; i++ )
+                                               newDN[0][i] = tmpDN[i];
+                               }
+                               newDN[0][nrdns] = NULL;
+                               rc = LDAP_SUCCESS;
+                       }
                        goto return_result;
                }
        }
        
 parsing_error:;
        if ( newRDN ) {
                        goto return_result;
                }
        }
        
 parsing_error:;
        if ( newRDN ) {
-               ldapava_free_rdn( newRDN );
+               ldap_rdnfree( newRDN );
        }
 
        }
 
-       if ( newDN ) {
-               ldapava_free_dn( newDN );
-               newDN = NULL;
+       for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
+               ldap_rdnfree( tmpDN[nrdns] );
        }
 
 return_result:;
 
        }
 
 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 (( "getdn", LDAP_LEVEL_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 );
        *dn = newDN;
        
        return( rc );
@@ -1046,29 +856,58 @@ return_result:;
  * corresponds to the rdn separator or to '\0' in case the string is over.
  */
 int
  * corresponds to the rdn separator or to '\0' in case the string is over.
  */
 int
-ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
+ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
+       char **n_in, unsigned flags )
+{
+       struct berval   bv;
+
+       assert( str );
+       assert( str[ 0 ] != '\0' );     /* FIXME: is this required? */
+
+       bv.bv_len = strlen( str );
+       bv.bv_val = (char *) str;
+
+       return ldap_bv2rdn( &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;
        const char      *p;
+       int             navas = 0;
        int             state = B4AVA;
        int             state = B4AVA;
-       int             rc = LDAP_INVALID_DN_SYNTAX;
+       int             rc = LDAP_DECODING_ERROR;
        int             attrTypeEncoding = LDAP_AVA_STRING, 
                        attrValueEncoding = LDAP_AVA_STRING;
 
        int             attrTypeEncoding = LDAP_AVA_STRING, 
                        attrValueEncoding = LDAP_AVA_STRING;
 
-       struct berval   *attrType = NULL;
-       struct berval   *attrValue = NULL;
+       struct berval   attrType = { 0, NULL };
+       struct berval   attrValue = { 0, NULL };
 
        LDAPRDN         *newRDN = NULL;
 
        LDAPRDN         *newRDN = NULL;
+       LDAPAVA         *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
+       int             num_slots = TMP_AVA_SLOTS;
+
+       char            *str;
+       ber_len_t       stoplen;
        
        
-       assert( str );
-       assert( rdn );
+       assert( bv );
+       assert( bv->bv_len );
+       assert( bv->bv_val );
+       assert( rdn || flags & LDAP_DN_SKIP );
        assert( n );
 
        assert( n );
 
-       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 ) ) {
        *n = 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:
        case LDAP_DN_FORMAT_LDAPV3:
        case LDAP_DN_FORMAT_LDAPV2:
        case LDAP_DN_FORMAT_DCE:
@@ -1077,14 +916,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:
        /* 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:
        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;
        }
 
        p = str;
@@ -1137,10 +983,6 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                                }
                        }
 
                                }
                        }
 
-                       state = B4ATTRTYPE;
-                       break;
-
-               case B4ATTRTYPE:
                        /* oid */
                        if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
                                state = B4OIDATTRTYPE;
                        /* oid */
                        if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
                                state = B4OIDATTRTYPE;
@@ -1159,8 +1001,8 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                                 * "OID." or "oid."
                                 */
                                if ( flags & LDAP_DN_PEDANTIC ) {
                                 * "OID." or "oid."
                                 */
                                if ( flags & LDAP_DN_PEDANTIC ) {
-                                       if ( !strncmp( p, "oid.", 4 )
-                                               || !strncmp( p, "OID.", 4 ) ) {
+                                       if ( !strncmp( p, "OID.", 4 )
+                                               || !strncmp( p, "oid.", 4 ) ) {
                                                p += 4;
                                                state = B4OIDATTRTYPE;
                                                break;
                                                p += 4;
                                                state = B4OIDATTRTYPE;
                                                break;
@@ -1179,19 +1021,15 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                
                case B4OIDATTRTYPE: {
                        int             err = LDAP_SUCCESS;
                
                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;
                        }
                                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;
                        attrTypeEncoding = LDAP_AVA_BINARY;
 
                        state = B4AVAEQUALS;
@@ -1206,7 +1044,7 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                         * the starting char has been found to be
                         * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
                         * FIXME: DCE attr types seem to have a more
                         * the starting char has been found to be
                         * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
                         * FIXME: DCE attr types seem to have a more
-                        * restrictive syntax
+                        * restrictive syntax (no '-' ...) 
                         */
                        for ( startPos = p++; p[ 0 ]; p++ ) {
                                if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
                         */
                        for ( startPos = p++; p[ 0 ]; p++ ) {
                                if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
@@ -1243,18 +1081,6 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                                goto parsing_error;
                        }
                        
                                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;
 
                        /*
                        attrTypeEncoding = LDAP_AVA_STRING;
 
                        /*
@@ -1264,6 +1090,14 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                         */
                        
                        state = B4AVAEQUALS;
                         */
                        
                        state = B4AVAEQUALS;
+
+                       if ( flags & LDAP_DN_SKIP ) {
+                               break;
+                       }
+
+                       attrType.bv_val = (char *)startPos;
+                       attrType.bv_len = len;
+
                        break;
                }
                                
                        break;
                }
                                
@@ -1328,22 +1162,29 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                         * LDAPv2 allows the attribute value to be quoted;
                         * also, IA5 values are expected, in principle
                         */
                         * LDAPv2 allows the attribute value to be quoted;
                         * also, IA5 values are expected, in principle
                         */
-                       if ( LDAP_DN_LDAPV2( flags ) ) {
+                       if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
                                if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
                                        p++;
                                        state = B4IA5VALUEQUOTED;
                                        break;
                                }
 
                                if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
                                        p++;
                                        state = B4IA5VALUEQUOTED;
                                        break;
                                }
 
-                               state = B4IA5VALUE;
-                               break;
+                               if ( LDAP_DN_LDAPV2( flags ) ) {
+                                       state = B4IA5VALUE;
+                                       break;
+                               }
                        }
 
                        /*
                         * here STRING means RFC 2253 string
                         * FIXME: what about DCE strings? 
                         */
                        }
 
                        /*
                         * here STRING means RFC 2253 string
                         * FIXME: what about DCE strings? 
                         */
-                       state = B4STRINGVALUE;
+                       if ( !p[ 0 ] ) {
+                               /* empty value */
+                               state = GOTAVA;
+                       } else {
+                               state = B4STRINGVALUE;
+                       }
                        break;
 
                case B4BINARYVALUE:
                        break;
 
                case B4BINARYVALUE:
@@ -1356,18 +1197,17 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
 
                case B4STRINGVALUE:
                        switch ( LDAP_DN_FORMAT( flags ) ) {
 
                case B4STRINGVALUE:
                        switch ( LDAP_DN_FORMAT( flags ) ) {
+                       case LDAP_DN_FORMAT_LDAP:
                        case LDAP_DN_FORMAT_LDAPV3:
                        case LDAP_DN_FORMAT_LDAPV3:
-                               if ( str2strval( p, &attrValue, 
-                                                       &p, flags, 
+                               if ( str2strval( p, stoplen - ( p - str ),
+                                                       &attrValue, &p, flags, 
                                                        &attrValueEncoding ) ) {
                                        goto parsing_error;
                                }
                                break;
 
                        case LDAP_DN_FORMAT_DCE:
                                                        &attrValueEncoding ) ) {
                                        goto parsing_error;
                                }
                                break;
 
                        case LDAP_DN_FORMAT_DCE:
-                               /* FIXME: does DCE use UTF-8? */
-                               if ( DCE2strval( p, &attrValue, 
-                                                       &p, flags ) ) {
+                               if ( DCE2strval( p, &attrValue, &p, flags ) ) {
                                        goto parsing_error;
                                }
                                break;
                                        goto parsing_error;
                                }
                                break;
@@ -1399,33 +1239,60 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                        break;
 
                case GOTAVA: {
                        break;
 
                case GOTAVA: {
-                       LDAPAVA *ava;
-                       LDAPRDN *rdn;
                        int     rdnsep = 0;
 
                        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 );
+                               
+                               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_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;
+                               }
                        }
                        }
-                       newRDN = rdn;
                        
                        /* 
                        
                        /* 
-                        * if we got an AVA separator ('+', | ',' * for DCE ) 
+                        * if we got an AVA separator ('+', or ',' for DCE ) 
                         * we expect a new AVA for this RDN; otherwise 
                         * we add the RDN to the DN
                         */
                        switch ( LDAP_DN_FORMAT( flags ) ) {
                         * we expect a new AVA for this RDN; otherwise 
                         * we add the RDN to the DN
                         */
                        switch ( LDAP_DN_FORMAT( flags ) ) {
+                       case LDAP_DN_FORMAT_LDAP:
                        case LDAP_DN_FORMAT_LDAPV3:
                        case LDAP_DN_FORMAT_LDAPV2:
                                if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
                        case LDAP_DN_FORMAT_LDAPV3:
                        case LDAP_DN_FORMAT_LDAPV2:
                                if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
@@ -1445,13 +1312,30 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                                 * the RDN is over, phew
                                 */
                                *n = p;
                                 * the RDN is over, phew
                                 */
                                *n = p;
+                               if ( !( flags & LDAP_DN_SKIP ) ) {
+                                       newRDN = (LDAPRDN *)LDAP_MALLOC( sizeof(LDAPRDN)
+                                               + sizeof(LDAPAVA *) * (navas+1) );
+                                       if ( newRDN == NULL ) {
+                                               rc = LDAP_NO_MEMORY;
+                                               goto parsing_error;
+                                       } else {
+                                               int i;
+
+                                               newRDN[0] = (LDAPAVA**)(newRDN+1);
+
+                                               for (i=0; i<navas; i++)
+                                                       newRDN[0][i] = tmpRDN[i];
+                                               newRDN[0][i] = NULL;
+                                       }
+
+                               }
                                rc = LDAP_SUCCESS;
                                goto return_result;
                        }
 
                        /* they should have been used in an AVA */
                                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;
                        
                        p++;
                        state = B4AVA;
@@ -1463,26 +1347,28 @@ ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
                        goto parsing_error;
                }
        }
                        goto parsing_error;
                }
        }
+       *n = p;
        
 parsing_error:;
        /* They are set to NULL after they're used in an AVA */
        
 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 ) {
+               free( attrValue.bv_val );
        }
 
        }
 
-       if ( newRDN ) {
-               ldapava_free_rdn( newRDN );
+       for ( navas-- ; navas >= 0; navas-- ) {
+               ldap_avafree( tmpRDN[navas] );
        }
 
 return_result:;
 
        }
 
 return_result:;
 
-       Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n", 
-                       *n - p, str, rc );
-       *rdn = newRDN;
+       if ( tmpRDN != tmpRDN_ ) {
+               LDAP_FREE( tmpRDN );
+       }
+
+       if ( rdn ) {
+               *rdn = newRDN;
+       }
        
        return( rc );
 }
        
        return( rc );
 }
@@ -1493,27 +1379,24 @@ return_result:;
  * '\' + HEXPAIR(p) -> unhex(p)
  */
 static int
  * '\' + 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;
-       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 );
        assert( val );
        assert( next );
 
-       *val = NULL;
        *next = 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 ( 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;
                        }
                                escapes++;
                                continue;
                        }
@@ -1540,16 +1423,21 @@ str2strval( const char *str, struct berval **val, const char **next, unsigned fl
                                return( 1 );
                        }
                        /* 
                                return( 1 );
                        }
                        /* 
-                        * FIXME: we allow escaping 
+                        * we do not allow escaping 
                         * of chars that don't need 
                         * to and do not belong to 
                         * 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_VALUE_END( p[ 0 ] ) ) {
+               } 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 ] ) ) ) {
                        break;
 
                } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
                        break;
 
                } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
@@ -1581,62 +1469,63 @@ str2strval( const char *str, struct berval **val, const char **next, unsigned fl
                }
        }
 
                }
        }
 
+       *next = p;
+       if ( flags & LDAP_DN_SKIP ) {
+               return( 0 );
+       }
+
        /*
         * FIXME: test memory?
         */
        /*
         * 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_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;
 
 
        } else {
                ber_len_t       s, d;
 
-               ( *val )->bv_val = LDAP_MALLOC( len + 1 );
+               val->bv_val = LDAP_MALLOC( len + 1 );
                for ( s = 0, d = 0; d < len; ) {
                        if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
                                s++;
                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 );
                                                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 {
                                        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 {
                                }
 
                        } 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
        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 )
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len, escapes;
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len, escapes;
@@ -1645,7 +1534,6 @@ DCE2strval( const char *str, struct berval **val, const char **next, unsigned fl
        assert( val );
        assert( next );
 
        assert( val );
        assert( next );
 
-       *val = NULL;
        *next = NULL;
        
        for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
        *next = NULL;
        
        for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
@@ -1688,17 +1576,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;
        len = ( endPos ? endPos : p ) - startPos - escapes;
-       *val = LDAP_MALLOC( sizeof( struct berval ) );
-       ( *val )->bv_len = len;
+       val->bv_len = len;
        if ( escapes == 0 ){
        if ( escapes == 0 ){
-               ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
+               val->bv_val = LDAP_STRNDUP( startPos, len );
 
        } else {
                ber_len_t       s, d;
 
 
        } else {
                ber_len_t       s, d;
 
-               ( *val )->bv_val = LDAP_MALLOC( len + 1 );
+               val->bv_val = LDAP_MALLOC( len + 1 );
                for ( s = 0, d = 0; d < len; ) {
                        /*
                         * This point is reached only if escapes 
                for ( s = 0, d = 0; d < len; ) {
                        /*
                         * This point is reached only if escapes 
@@ -1709,19 +1600,17 @@ DCE2strval( const char *str, struct berval **val, const char **next, unsigned fl
                                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
        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 )
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len, escapes;
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len, escapes;
@@ -1730,7 +1619,6 @@ IA52strval( const char *str, struct berval **val, const char **next, unsigned fl
        assert( val );
        assert( next );
 
        assert( val );
        assert( next );
 
-       *val = NULL;
        *next = NULL;
 
        /*
        *next = NULL;
 
        /*
@@ -1769,32 +1657,35 @@ IA52strval( const char *str, struct berval **val, const char **next, unsigned fl
                /* no op */
        }
 
                /* no op */
        }
 
-       *val = LDAP_MALLOC( sizeof( struct berval ) );
+       *next = p;
+       if ( flags & LDAP_DN_SKIP ) {
+               return( 0 );
+       }
+
        len = ( endPos ? endPos : p ) - startPos - escapes;
        len = ( endPos ? endPos : p ) - startPos - escapes;
-       ( *val )->bv_len = len;
+       val->bv_len = len;
        if ( escapes == 0 ) {
        if ( escapes == 0 ) {
-               ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
+               val->bv_val = LDAP_STRNDUP( startPos, len );
 
        } else {
                ber_len_t       s, d;
                
 
        } else {
                ber_len_t       s, d;
                
-               ( *val )->bv_val = LDAP_MALLOC( len + 1 );
+               val->bv_val = LDAP_MALLOC( len + 1 );
                for ( s = 0, d = 0; d < len; ) {
                        if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
                                s++;
                        }
                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
 
        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 )
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len;
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len;
@@ -1804,7 +1695,6 @@ quotedIA52strval( const char *str, struct berval **val, const char **next, unsig
        assert( val );
        assert( next );
 
        assert( val );
        assert( next );
 
-       *val = NULL;
        *next = NULL;
 
        /* initial quote already eaten */
        *next = NULL;
 
        /* initial quote already eaten */
@@ -1856,31 +1746,33 @@ quotedIA52strval( const char *str, struct berval **val, const char **next, unsig
                /* no op */
        }
 
                /* no op */
        }
 
+       *next = p;
+       if ( flags & LDAP_DN_SKIP ) {
+               return( 0 );
+       }
+
        len = endPos - startPos - escapes;
        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 ) {
        if ( escapes == 0 ) {
-               ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
+               val->bv_val = LDAP_STRNDUP( startPos, len );
 
        } else {
                ber_len_t       s, d;
                
 
        } else {
                ber_len_t       s, d;
                
-               ( *val )->bv_val = LDAP_MALLOC( len + 1 );
-               ( *val )->bv_len = len;
+               val->bv_val = LDAP_MALLOC( len + 1 );
+               val->bv_len = len;
 
                for ( s = d = 0; d < len; ) {
                        if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
                                s++;
                        }
 
                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 );
 }
 
        return( 0 );
 }
 
@@ -1899,9 +1791,10 @@ hexstr2bin( const char *str, char *c )
                *c = c1 - '0';
 
        } else {
                *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;
                }
        }
                        *c = c1 - 'a' + 10;
                }
        }
@@ -1912,9 +1805,10 @@ hexstr2bin( const char *str, char *c )
                *c += c2 - '0';
                
        } else {
                *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;
                }
        }
                        *c += c2 - 'a' + 10;
                }
        }
@@ -1923,7 +1817,7 @@ hexstr2bin( const char *str, char *c )
 }
 
 static int
 }
 
 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 )
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len;
 {
        const char      *p, *startPos, *endPos = NULL;
        ber_len_t       len;
@@ -1933,18 +1827,23 @@ hexstr2binval( const char *str, struct berval **val, const char **next, unsigned
        assert( val );
        assert( next );
 
        assert( val );
        assert( next );
 
-       *val = NULL;
        *next = NULL;
 
        for ( startPos = p = str; p[ 0 ]; p += 2 ) {
                switch ( LDAP_DN_FORMAT( flags ) ) {
                case LDAP_DN_FORMAT_LDAPV3:
        *next = NULL;
 
        for ( startPos = p = str; p[ 0 ]; p += 2 ) {
                switch ( LDAP_DN_FORMAT( flags ) ) {
                case LDAP_DN_FORMAT_LDAPV3:
-               case LDAP_DN_FORMAT_LDAPV2:
                        if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
                                goto end_of_value;
                        }
                        break;
 
                        if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
                                goto end_of_value;
                        }
                        break;
 
+               case LDAP_DN_FORMAT_LDAP:
+               case LDAP_DN_FORMAT_LDAPV2:
+                       if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
+                               goto end_of_value;
+                       }
+                       break;
+
                case LDAP_DN_FORMAT_DCE:
                        if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
                                goto end_of_value;
                case LDAP_DN_FORMAT_DCE:
                        if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
                                goto end_of_value;
@@ -1961,12 +1860,18 @@ hexstr2binval( const char *str, struct berval **val, const char **next, unsigned
                        for ( ; p[ 0 ]; p++ ) {
                                switch ( LDAP_DN_FORMAT( flags ) ) {
                                case LDAP_DN_FORMAT_LDAPV3:
                        for ( ; p[ 0 ]; p++ ) {
                                switch ( LDAP_DN_FORMAT( flags ) ) {
                                case LDAP_DN_FORMAT_LDAPV3:
-                               case LDAP_DN_FORMAT_LDAPV2:
                                        if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
                                                goto end_of_value;
                                        }
                                        break;
 
                                        if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
                                                goto end_of_value;
                                        }
                                        break;
 
+                               case LDAP_DN_FORMAT_LDAP:
+                               case LDAP_DN_FORMAT_LDAPV2:
+                                       if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
+                                               goto end_of_value;
+                                       }
+                                       break;
+
                                case LDAP_DN_FORMAT_DCE:
                                        if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
                                                goto end_of_value;
                                case LDAP_DN_FORMAT_DCE:
                                        if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
                                                goto end_of_value;
@@ -1984,19 +1889,18 @@ hexstr2binval( const char *str, struct berval **val, const char **next, unsigned
 
 end_of_value:;
 
 
 end_of_value:;
 
+       *next = p;
+       if ( flags & LDAP_DN_SKIP ) {
+               return( 0 );
+       }
+
        len = ( ( endPos ? endPos : p ) - startPos ) / 2;
        /* must be even! */
        len = ( ( endPos ? endPos : p ) - startPos ) / 2;
        /* must be even! */
-       assert( 2 * len == ( endPos ? endPos : p ) - startPos );
-
-       *val = LDAP_MALLOC( sizeof( struct berval ) );
-       if ( *val == NULL ) {
-               return( LDAP_NO_MEMORY );
-       }
+       assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
 
 
-       ( *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_MALLOC( len + 1 );
+       if ( val->bv_val == NULL ) {
                return( LDAP_NO_MEMORY );
        }
 
                return( LDAP_NO_MEMORY );
        }
 
@@ -2005,11 +1909,10 @@ end_of_value:;
 
                hexstr2bin( &startPos[ s ], &c );
 
 
                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 );
 }
 
        return( 0 );
 }
@@ -2020,7 +1923,7 @@ end_of_value:;
 static int
 byte2hexpair( const char *val, char *pair )
 {
 static int
 byte2hexpair( const char *val, char *pair )
 {
-       static const char       hexdig[] = "0123456789abcdef";
+       static const char       hexdig[] = "0123456789ABCDEF";
 
        assert( val );
        assert( pair );
 
        assert( val );
        assert( pair );
@@ -2072,6 +1975,10 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
 {
        ber_len_t       l, cl = 1;
        char            *p;
 {
        ber_len_t       l, cl = 1;
        char            *p;
+       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 );
        assert( len );
@@ -2081,8 +1988,18 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
                return( 0 );
        }
 
                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 );
                if ( cl == 0 ) {
                        /* illegal utf-8 char! */
                        return( -1 );
@@ -2091,17 +2008,35 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
                        ber_len_t cnt;
 
                        for ( cnt = 1; cnt < cl; cnt++ ) {
                        ber_len_t cnt;
 
                        for ( cnt = 1; cnt < cl; cnt++ ) {
-                               if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
+                               if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
                                        return( -1 );
                                }
                        }
                                        return( -1 );
                                }
                        }
-                       /* need to escape it */
-                       l += 3 * cl;
+                       l += escaped_byte_len * cl;
 
 
-               } else if ( ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
-                               || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
-                               || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
-                       l += 2;
+               } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
+                               || ( 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 
+                                * 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++;
 
                } else {
                        l++;
@@ -2136,9 +2071,45 @@ 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; ) {
         * 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 );
                
                
-               if ( cl > 1 ) {
+               /* 
+                * 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 ) ) 
+#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 ] ) )
+                               || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
+
+#endif /* ! PRETTY_ESCAPE */
+                               ) {
                        for ( ; cl--; ) {
                                str[ d++ ] = '\\';
                                byte2hexpair( &val->bv_val[ s ], &str[ d ] );
                        for ( ; cl--; ) {
                                str[ d++ ] = '\\';
                                byte2hexpair( &val->bv_val[ s ], &str[ d ] );
@@ -2146,12 +2117,25 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
                                d += 2;
                        }
 
                                d += 2;
                        }
 
+               } else if ( cl > 1 ) {
+                       for ( ; cl--; ) {
+                               str[ d++ ] = val->bv_val[ s++ ];
+                       }
+
                } else {
                } else {
-                       if ( ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
-                                       || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
-                                       || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) ) {
+#ifdef PRETTY_ESCAPE
+                       if ( LDAP_DN_NEEDESCAPE( 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++ ] = '\\';
                                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++ ];
                }
        }
                        str[ d++ ] = val->bv_val[ s++ ];
                }
        }
@@ -2186,9 +2170,9 @@ strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
 
        } else {
                for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
 
        } else {
                for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
-                       if ( ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
-                                       || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
-                                       || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
+                       if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
+                                       || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
+                                       || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
                                l += 2;
 
                        } else {
                                l += 2;
 
                        } else {
@@ -2234,9 +2218,9 @@ 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; ) {
                 */
 
                for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
-                       if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
-                                       || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
-                                       || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) ) {
+                       if ( LDAP_DN_NEEDESCAPE( 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++ ] = '\\';
                        }
                        str[ d++ ] = val->bv_val[ s++ ];
                                str[ d++ ] = '\\';
                        }
                        str[ d++ ] = val->bv_val[ s++ ];
@@ -2422,31 +2406,34 @@ 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",
 
 /*
  * 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
  * 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 */
 {
        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 );
 
        /* we are guaranteed there's enough memory in str */
 
        /* sanity */
        assert( dn );
-       assert( str );
+       assert( bv );
        assert( iRDN );
        assert( iRDN );
-       assert( *iRDN > 0 );
+       assert( *iRDN >= 0 );
+
+       str = bv->bv_val + pos;
 
        for ( i = *iRDN; i >= 0; i-- ) {
                LDAPRDN         *rdn;
                LDAPAVA         *ava;
 
 
        for ( i = *iRDN; i >= 0; i-- ) {
                LDAPRDN         *rdn;
                LDAPAVA         *ava;
 
-               assert( dn[ i ][ 0 ] );
-               rdn = dn[ i ][ 0 ];
+               assert( dn[ 0 ][ i ] );
+               rdn = dn[ 0 ][ i ];
 
                assert( rdn[ 0 ][ 0 ] );
                ava = rdn[ 0 ][ 0 ];
 
                assert( rdn[ 0 ][ 0 ] );
                ava = rdn[ 0 ][ 0 ];
@@ -2459,26 +2446,27 @@ dn2domain( LDAPDN *dn, char *str, int *iRDN )
                
                if ( first ) {
                        first = 0;
                
                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 {
 
                } 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;
                }
        }
 
        *iRDN = i;
+       bv->bv_len = pos + l - 1;
 
        return( domain );
 }
 
 static int
 
        return( domain );
 }
 
 static int
-rdn2strlen( LDAPRDN *rdn, 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;
         int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
 {
        int             iAVA;
@@ -2486,20 +2474,21 @@ rdn2strlen( LDAPRDN *rdn, ber_len_t *len,
 
        *len = 0;
 
 
        *len = 0;
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
 
                /* len(type) + '=' + '+' | ',' */
 
                /* 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 */
 
                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;
 
                } else {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
                        
                        
-                       if ( ( *s2l )( ava->la_value, ava->la_flags, &vl ) ) {
+                       if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                                return( -1 );
                        }
                        l += vl;
@@ -2512,38 +2501,38 @@ rdn2strlen( LDAPRDN *rdn, ber_len_t *len,
 }
 
 static int
 }
 
 static int
-rdn2str( LDAPRDN *rdn, char *str, 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;
 
        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 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ 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++ ] = '#';
 
                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 );
                        }
                                return( -1 );
                        }
-                       l += 2 * ava->la_value->bv_len;
+                       l += 2 * ava->la_value.bv_len;
 
                } else {
                        ber_len_t       vl;
 
                } else {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
 
 
-                       if ( ( *s2s )( ava->la_value, &str[ l ], 
-                                       ava->la_flags, &vl ) ) {
+                       if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                }
                                return( -1 );
                        }
                        l += vl;
                }
-               str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
+               str[ l++ ] = ( rdn[ 0 ][ iAVA + 1 ] ? '+' : ',' );
        }
 
        *len = l;
        }
 
        *len = l;
@@ -2552,30 +2541,30 @@ rdn2str( LDAPRDN *rdn, char *str, ber_len_t *len,
 }
 
 static int
 }
 
 static int
-rdn2DCEstrlen( LDAPRDN *rdn, ber_len_t *len )
+rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
 {
        int             iAVA;
        ber_len_t       l = 0;
 
        *len = 0;
 
 {
        int             iAVA;
        ber_len_t       l = 0;
 
        *len = 0;
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
 
                /* len(type) + '=' + ',' | '/' */
 
                /* len(type) + '=' + ',' | '/' */
-               l += ava->la_attr->bv_len + 2;
+               l += ava->la_attr.bv_len + 2;
 
                switch ( ava->la_flags ) {
                case LDAP_AVA_BINARY:
                        /* octothorpe + twice the length */
 
                switch ( ava->la_flags ) {
                case LDAP_AVA_BINARY:
                        /* octothorpe + twice the length */
-                       l += 1 + 2 * ava->la_value->bv_len;
+                       l += 1 + 2 * ava->la_value.bv_len;
                        break;
 
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
                        break;
 
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
                        
                        
-                       if ( strval2DCEstrlen( ava->la_value, 
-                                       ava->la_flags, &vl ) ) {
+                       if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                                return( -1 );
                        }
                        l += vl;
@@ -2593,13 +2582,13 @@ rdn2DCEstrlen( LDAPRDN *rdn, ber_len_t *len )
 }
 
 static int
 }
 
 static int
-rdn2DCEstr( LDAPRDN *rdn, char *str, 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;
 
 {
        int             iAVA;
        ber_len_t       l = 0;
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
 
                if ( first ) {
                        first = 0;
 
                if ( first ) {
                        first = 0;
@@ -2607,26 +2596,26 @@ rdn2DCEstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first )
                        str[ l++ ] = ( iAVA ? ',' : '/' );
                }
 
                        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:
                        str[ l++ ] = '#';
 
                str[ l++ ] = '=';
 
                switch ( ava->la_flags ) {
                        case LDAP_AVA_BINARY:
                        str[ l++ ] = '#';
-                       if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
+                       if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
                                return( -1 );
                        }
                                return( -1 );
                        }
-                       l += 2 * ava->la_value->bv_len;
+                       l += 2 * ava->la_value.bv_len;
                        break;
 
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
                        break;
 
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
 
 
-                       if ( strval2DCEstr( ava->la_value, &str[ l ], 
-                                       ava->la_flags, &vl ) ) {
+                       if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                                return( -1 );
                        }
                        l += vl;
@@ -2644,7 +2633,7 @@ rdn2DCEstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first )
 }
 
 static int
 }
 
 static int
-rdn2UFNstrlen( LDAPRDN *rdn, ber_len_t *len )
+rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
 {
        int             iAVA;
        ber_len_t       l = 0;
 {
        int             iAVA;
        ber_len_t       l = 0;
@@ -2654,22 +2643,22 @@ rdn2UFNstrlen( LDAPRDN *rdn, ber_len_t *len )
 
        *len = 0;
 
 
        *len = 0;
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
 
                /* ' + ' | ', ' */
 
                /* ' + ' | ', ' */
-               l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
+               l += ( rdn[ 0 ][ iAVA + 1 ] ? 3 : 2 );
 
                /* FIXME: are binary values allowed in UFN? */
                if ( ava->la_flags & LDAP_AVA_BINARY ) {
                        /* octothorpe + twice the value */
 
                /* 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;
 
                } else {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
 
 
-                       if ( strval2strlen( ava->la_value, ava->la_flags, 
-                                               &vl ) ) {
+                       if ( strval2strlen( &ava->la_value, f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                                return( -1 );
                        }
                        l += vl;
@@ -2682,32 +2671,32 @@ rdn2UFNstrlen( LDAPRDN *rdn, ber_len_t *len )
 }
 
 static int
 }
 
 static int
-rdn2UFNstr( LDAPRDN *rdn, char *str, ber_len_t *len )
+rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
 {
        int             iAVA;
        ber_len_t       l = 0;
 
 {
        int             iAVA;
        ber_len_t       l = 0;
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
 
                if ( ava->la_flags & LDAP_AVA_BINARY ) {
                        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 );
                        }
                                return( -1 );
                        }
-                       l += 2 * ava->la_value->bv_len;
+                       l += 2 * ava->la_value.bv_len;
                        
                } else {
                        ber_len_t       vl;
                        
                } else {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
                        
                        
-                       if ( strval2str( ava->la_value, &str[ l ], 
-                                       ava->la_flags, &vl ) ) {
+                       if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                }
 
                                return( -1 );
                        }
                        l += vl;
                }
 
-               if ( rdn[ iAVA + 1 ]) {
+               if ( rdn[ 0 ][ iAVA + 1 ]) {
                        AC_MEMCPY( &str[ l ], " + ", 3 );
                        l += 3;
 
                        AC_MEMCPY( &str[ l ], " + ", 3 );
                        l += 3;
 
@@ -2723,7 +2712,7 @@ rdn2UFNstr( LDAPRDN *rdn, char *str, ber_len_t *len )
 }
 
 static int
 }
 
 static int
-rdn2ADstrlen( LDAPRDN *rdn, ber_len_t *len )
+rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
 {
        int             iAVA;
        ber_len_t       l = 0;
 {
        int             iAVA;
        ber_len_t       l = 0;
@@ -2733,8 +2722,8 @@ rdn2ADstrlen( LDAPRDN *rdn, ber_len_t *len )
 
        *len = 0;
 
 
        *len = 0;
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
 
                /* ',' | '/' */
                l++;
 
                /* ',' | '/' */
                l++;
@@ -2743,14 +2732,14 @@ rdn2ADstrlen( LDAPRDN *rdn, ber_len_t *len )
                switch ( ava->la_flags ) {
                case LDAP_AVA_BINARY:
                        /* octothorpe + twice the value */
                switch ( ava->la_flags ) {
                case LDAP_AVA_BINARY:
                        /* octothorpe + twice the value */
-                       l += 1 + 2 * ava->la_value->bv_len;
+                       l += 1 + 2 * ava->la_value.bv_len;
                        break;
 
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
                        break;
 
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
 
 
-                       if ( strval2ADstrlen( ava->la_value, 
-                                       ava->la_flags, &vl ) ) {
+                       if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                                return( -1 );
                        }
                        l += vl;
@@ -2768,13 +2757,13 @@ rdn2ADstrlen( LDAPRDN *rdn, ber_len_t *len )
 }
 
 static int
 }
 
 static int
-rdn2ADstr( LDAPRDN *rdn, char *str, 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;
 
 {
        int             iAVA;
        ber_len_t       l = 0;
 
-       for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
-               LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
+       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
 
                if ( first ) {
                        first = 0;
 
                if ( first ) {
                        first = 0;
@@ -2785,17 +2774,17 @@ rdn2ADstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first )
                switch ( ava->la_flags ) {
                case LDAP_AVA_BINARY:
                        str[ l++ ] = '#';
                switch ( ava->la_flags ) {
                case LDAP_AVA_BINARY:
                        str[ l++ ] = '#';
-                       if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
+                       if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
                                return( -1 );
                        }
                                return( -1 );
                        }
-                       l += 2 * ava->la_value->bv_len;
+                       l += 2 * ava->la_value.bv_len;
                        break;
                        
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
                        break;
                        
                case LDAP_AVA_STRING: {
                        ber_len_t       vl;
+                       unsigned        f = flags | ava->la_flags;
                        
                        
-                       if ( strval2ADstr( ava->la_value, &str[ l ], 
-                                       ava->la_flags, &vl ) ) {
+                       if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
                                return( -1 );
                        }
                        l += vl;
                                return( -1 );
                        }
                        l += vl;
@@ -2821,14 +2810,34 @@ rdn2ADstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first )
  */
 int
 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
  */
 int
 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
+{
+       struct berval bv;
+       int rc;
+
+       assert( str );
+
+       if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
+               return LDAP_PARAM_ERROR;
+       }
+
+       rc = ldap_rdn2bv( rdn, &bv, flags );
+       *str = bv.bv_val;
+       return rc;
+}
+
+int
+ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags )
 {
        int             rc, back;
        ber_len_t       l;
        
 {
        int             rc, back;
        ber_len_t       l;
        
-       assert( str );
+       assert( bv );
+
+       bv->bv_len = 0;
+       bv->bv_val = NULL;
 
        if ( rdn == NULL ) {
 
        if ( rdn == NULL ) {
-               *str = LDAP_STRDUP( "" );
+               bv->bv_val = LDAP_STRDUP( "" );
                return( LDAP_SUCCESS );
        }
 
                return( LDAP_SUCCESS );
        }
 
@@ -2836,83 +2845,83 @@ ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
         * This routine wastes "back" bytes at the end of the string
         */
 
         * This routine wastes "back" bytes at the end of the string
         */
 
-       *str = NULL;
        switch ( LDAP_DN_FORMAT( flags ) ) {
        case LDAP_DN_FORMAT_LDAPV3:
        switch ( LDAP_DN_FORMAT( flags ) ) {
        case LDAP_DN_FORMAT_LDAPV3:
-               if ( rdn2strlen( rdn, &l, strval2strlen ) ) {
-                       return( LDAP_OTHER );
+               if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
+                       return LDAP_DECODING_ERROR;
                }
                break;
 
        case LDAP_DN_FORMAT_LDAPV2:
                }
                break;
 
        case LDAP_DN_FORMAT_LDAPV2:
-               if ( rdn2strlen( rdn, &l, strval2IA5strlen ) ) {
-                       return( LDAP_OTHER );
+               if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
+                       return LDAP_DECODING_ERROR;
                }
                break;
 
        case LDAP_DN_FORMAT_UFN:
                }
                break;
 
        case LDAP_DN_FORMAT_UFN:
-               if ( rdn2UFNstrlen( rdn, &l ) ) {
-                       return( LDAP_OTHER );
+               if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
+                       return LDAP_DECODING_ERROR;
                }
                break;
 
        case LDAP_DN_FORMAT_DCE:
                }
                break;
 
        case LDAP_DN_FORMAT_DCE:
-               if ( rdn2DCEstrlen( rdn, &l ) ) {
-                       return( LDAP_OTHER );
+               if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
+                       return LDAP_DECODING_ERROR;
                }
                break;
 
        case LDAP_DN_FORMAT_AD_CANONICAL:
                }
                break;
 
        case LDAP_DN_FORMAT_AD_CANONICAL:
-               if ( rdn2ADstrlen( rdn, &l ) ) {
-                       return( LDAP_OTHER );
+               if ( rdn2ADstrlen( rdn, flags, &l ) ) {
+                       return LDAP_DECODING_ERROR;
                }
                break;
 
        default:
                }
                break;
 
        default:
-               return( LDAP_OTHER );
+               return LDAP_PARAM_ERROR;
        }
 
        }
 
-       *str = LDAP_MALLOC( l + 1 );
+       bv->bv_val = LDAP_MALLOC( l + 1 );
 
        switch ( LDAP_DN_FORMAT( flags ) ) {
        case LDAP_DN_FORMAT_LDAPV3:
 
        switch ( LDAP_DN_FORMAT( flags ) ) {
        case LDAP_DN_FORMAT_LDAPV3:
-               rc = rdn2str( rdn, *str, &l, strval2str );
+               rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
                back = 1;
                break;
 
        case LDAP_DN_FORMAT_LDAPV2:
                back = 1;
                break;
 
        case LDAP_DN_FORMAT_LDAPV2:
-               rc = rdn2str( rdn, *str, &l, strval2IA5str );
+               rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
                back = 1;
                break;
 
        case LDAP_DN_FORMAT_UFN:
                back = 1;
                break;
 
        case LDAP_DN_FORMAT_UFN:
-               rc = rdn2UFNstr( rdn, *str, &l );
+               rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
                back = 2;
                break;
 
        case LDAP_DN_FORMAT_DCE:
                back = 2;
                break;
 
        case LDAP_DN_FORMAT_DCE:
-               rc = rdn2DCEstr( rdn, *str, &l, 1 );
+               rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
                back = 0;
                break;
 
        case LDAP_DN_FORMAT_AD_CANONICAL:
                back = 0;
                break;
 
        case LDAP_DN_FORMAT_AD_CANONICAL:
-               rc = rdn2ADstr( rdn, *str, &l, 1 );
+               rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
                back = 0;
                break;
 
        default:
                /* need at least one of the previous */
                back = 0;
                break;
 
        default:
                /* need at least one of the previous */
-               return( LDAP_OTHER );
+               return LDAP_PARAM_ERROR;
        }
 
        if ( rc ) {
        }
 
        if ( rc ) {
-               ldap_memfree( *str );
-               return( LDAP_OTHER );
+               ldap_memfree( bv->bv_val );
+               return rc;
        }
 
        }
 
-       ( *str )[ l - back ] = '\0';
+       bv->bv_len = l - back;
+       bv->bv_val[ bv->bv_len ] = '\0';
 
 
-       return( LDAP_SUCCESS );
+       return LDAP_SUCCESS;
 }
 
 /*
 }
 
 /*
@@ -2928,27 +2937,48 @@ ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
  *      use binary encoded BER
  */ 
 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
  *      use binary encoded BER
  */ 
 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
+{
+       struct berval bv;
+       int rc;
+
+       assert( str );
+
+       if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
+               return LDAP_PARAM_ERROR;
+       }
+       
+       rc = ldap_dn2bv( dn, &bv, flags );
+       *str = bv.bv_val;
+       return rc;
+}
+
+int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
 {
        int             iRDN;
 {
        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 );
 
        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 );
-
-       Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
+       assert( bv );
+       bv->bv_len = 0;
+       bv->bv_val = NULL;
 
 
-       *str = NULL;
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_ARGS, "=> ldap_dn2bv(%u)\n%s%s", 
+               flags, "", "" ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" );
+#endif
 
        /* 
         * a null dn means an empty dn string 
         * FIXME: better raise an error?
         */
        if ( dn == NULL ) {
 
        /* 
         * a null dn means an empty dn string 
         * FIXME: better raise an error?
         */
        if ( dn == NULL ) {
-               *str = LDAP_STRDUP( "" );
+               bv->bv_val = LDAP_STRDUP( "" );
                return( LDAP_SUCCESS );
        }
 
                return( LDAP_SUCCESS );
        }
 
@@ -2956,36 +2986,37 @@ int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
        case LDAP_DN_FORMAT_LDAPV3:
                sv2l = strval2strlen;
                sv2s = strval2str;
        case LDAP_DN_FORMAT_LDAPV3:
                sv2l = strval2strlen;
                sv2s = strval2str;
-               goto got_funcs;
 
 
+               if( 0 ) {
        case LDAP_DN_FORMAT_LDAPV2:
        case LDAP_DN_FORMAT_LDAPV2:
-               sv2l = strval2IA5strlen;
-               sv2s = strval2IA5str;
-got_funcs:
-               
-               for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
+                       sv2l = strval2IA5strlen;
+                       sv2s = strval2IA5str;
+               }
+
+               for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
                        ber_len_t       rdnl;
                        ber_len_t       rdnl;
-                       LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                       if ( rdn2strlen( rdn, &rdnl, sv2l ) ) {
+                       if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
                                goto return_results;
                        }
 
                        len += rdnl;
                }
 
                                goto return_results;
                        }
 
                        len += rdnl;
                }
 
-               if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
+               if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
                        rc = LDAP_NO_MEMORY;
                        break;
                }
 
                        rc = LDAP_NO_MEMORY;
                        break;
                }
 
-               for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
+               for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
                        ber_len_t       rdnl;
                        ber_len_t       rdnl;
-                       LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                       if ( rdn2str( rdn, &( *str )[ l ], &rdnl, sv2s ) ) {
-                               LDAP_FREE( *str );
-                               *str = NULL;
+                       if ( rdn2str( rdn, &bv->bv_val[ l ], flags, 
+                                       &rdnl, sv2s ) ) {
+                               LDAP_FREE( bv->bv_val );
+                               bv->bv_val = NULL;
                                goto return_results;
                        }
                        l += rdnl;
                                goto return_results;
                        }
                        l += rdnl;
@@ -2997,13 +3028,13 @@ got_funcs:
                 * trim the last ',' (the allocated memory 
                 * is one byte longer than required)
                 */
                 * 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: {
 
                rc = LDAP_SUCCESS;
                break;
 
        case LDAP_DN_FORMAT_UFN: {
-
                /*
                 * FIXME: quoting from RFC 1781:
                 *
                /*
                 * FIXME: quoting from RFC 1781:
                 *
@@ -3023,7 +3054,7 @@ got_funcs:
         omitted, unless they are after an Organisation attribute or
         the first attribute is of type OrganisationalUnit.
 
         omitted, unless they are after an Organisation attribute or
         the first attribute is of type OrganisationalUnit.
 
-                * this should be the pedantic implementation.
+         * this should be the pedantic implementation.
                 *
                 * Here the standard implementation reflects
                 * the one historically provided by OpenLDAP
                 *
                 * Here the standard implementation reflects
                 * the one historically provided by OpenLDAP
@@ -3043,11 +3074,11 @@ got_funcs:
                int     last_iRDN = -1;
 #endif /* DC_IN_UFN */
 
                int     last_iRDN = -1;
 #endif /* DC_IN_UFN */
 
-               for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
+               for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
                        ber_len_t       rdnl;
                        ber_len_t       rdnl;
-                       LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                       if ( rdn2UFNstrlen( rdn, &rdnl ) ) {
+                       if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
                                goto return_results;
                        }
                        len += rdnl;
                                goto return_results;
                        }
                        len += rdnl;
@@ -3063,7 +3094,7 @@ got_funcs:
 #endif /* DC_IN_UFN */
                }
 
 #endif /* DC_IN_UFN */
                }
 
-               if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
+               if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
                        rc = LDAP_NO_MEMORY;
                        break;
                }
                        rc = LDAP_NO_MEMORY;
                        break;
                }
@@ -3071,13 +3102,14 @@ got_funcs:
 #ifdef DC_IN_UFN
                if ( leftmost_dc == -1 ) {
 #endif /* DC_IN_UFN */
 #ifdef DC_IN_UFN
                if ( leftmost_dc == -1 ) {
 #endif /* DC_IN_UFN */
-                       for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
+                       for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
                                ber_len_t       vl;
                                ber_len_t       vl;
-                               LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                               LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                               if ( rdn2UFNstr( rdn, &( *str )[ l ], &vl ) ) {
-                                       LDAP_FREE( *str );
-                                       *str = NULL;
+                               if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], 
+                                               flags, &vl ) ) {
+                                       LDAP_FREE( bv->bv_val );
+                                       bv->bv_val = NULL;
                                        goto return_results;
                                }
                                l += vl;
                                        goto return_results;
                                }
                                l += vl;
@@ -3087,26 +3119,28 @@ got_funcs:
                         * trim the last ', ' (the allocated memory 
                         * is two bytes longer than required)
                         */
                         * 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;
 #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 ];
+                               LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                               if ( rdn2UFNstr( rdn, &( *str )[ l ], &vl ) ) {
-                                       LDAP_FREE( *str );
-                                       *str = NULL;
+                               if ( rdn2UFNstr( rdn, &bv->bv_val[ l ], 
+                                               flags, &vl ) ) {
+                                       LDAP_FREE( bv->bv_val );
+                                       bv->bv_val = NULL;
                                        goto return_results;
                                }
                                l += vl;
                        }
 
                                        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_FREE( bv->bv_val );
+                               bv->bv_val = NULL;
                                goto return_results;
                        }
 
                                goto return_results;
                        }
 
@@ -3115,34 +3149,34 @@ got_funcs:
 #endif /* DC_IN_UFN */
                
                rc = LDAP_SUCCESS;
 #endif /* DC_IN_UFN */
                
                rc = LDAP_SUCCESS;
-               break;
-       }
 
 
-       case LDAP_DN_FORMAT_DCE:
+       } break;
 
 
-               for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
+       case LDAP_DN_FORMAT_DCE:
+               for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
                        ber_len_t       rdnl;
                        ber_len_t       rdnl;
-                       LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                       if ( rdn2DCEstrlen( rdn, &rdnl ) ) {
+                       if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
                                goto return_results;
                        }
 
                        len += rdnl;
                }
 
                                goto return_results;
                        }
 
                        len += rdnl;
                }
 
-               if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
+               if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
                        rc = LDAP_NO_MEMORY;
                        break;
                }
 
                for ( l = 0; iRDN--; ) {
                        ber_len_t       rdnl;
                        rc = LDAP_NO_MEMORY;
                        break;
                }
 
                for ( l = 0; iRDN--; ) {
                        ber_len_t       rdnl;
-                       LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                       if ( rdn2DCEstr( rdn, &( *str )[ l ], &rdnl, 0 ) ) {
-                               LDAP_FREE( *str );
-                               *str = NULL;
+                       if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags, 
+                                       &rdnl, 0 ) ) {
+                               LDAP_FREE( bv->bv_val );
+                               bv->bv_val = NULL;
                                goto return_results;
                        }
                        l += rdnl;
                                goto return_results;
                        }
                        l += rdnl;
@@ -3150,13 +3184,13 @@ got_funcs:
 
                assert( l == len );
 
 
                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: {
 
                rc = LDAP_SUCCESS;
                break;
 
        case LDAP_DN_FORMAT_AD_CANONICAL: {
-               
                /*
                 * Sort of UFN for DCE DNs: a slash ('/') separated
                 * global->local DN with no types; strictly speaking,
                /*
                 * Sort of UFN for DCE DNs: a slash ('/') separated
                 * global->local DN with no types; strictly speaking,
@@ -3165,38 +3199,38 @@ got_funcs:
                 * 
                 * Example:
                 * 
                 * 
                 * Example:
                 * 
-                *      "cn=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
+                *      "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
                 *
                 * will read
                 * 
                 *      "microsoft.com/People/Bill,Gates"
                 */ 
                 *
                 * will read
                 * 
                 *      "microsoft.com/People/Bill,Gates"
                 */ 
-               for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
+               for ( iRDN = 0, len = -1; dn[ 0 ][ iRDN ]; iRDN++ ) {
                        ber_len_t       rdnl;
                        ber_len_t       rdnl;
-                       LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                       if ( rdn2ADstrlen( rdn, &rdnl ) ) {
+                       if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
                                goto return_results;
                        }
 
                        len += rdnl;
                }
 
                                goto return_results;
                        }
 
                        len += rdnl;
                }
 
-               if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
+               if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
                        rc = LDAP_NO_MEMORY;
                        break;
                }
 
                iRDN--;
                        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 ) ) {
+                       for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
                                ber_len_t       rdnl;
                                ber_len_t       rdnl;
-                               LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                               LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                               if ( rdn2ADstr( rdn, &( *str )[ l ], 
-                                               &rdnl, 0 ) ) {
-                                       LDAP_FREE( *str );
-                                       *str = NULL;
+                               if ( rdn2ADstr( rdn, &bv->bv_val[ l ], 
+                                               flags, &rdnl, 0 ) ) {
+                                       LDAP_FREE( bv->bv_val );
+                                       bv->bv_val = NULL;
                                        goto return_results;
                                }
                                l += rdnl;
                                        goto return_results;
                                }
                                l += rdnl;
@@ -3211,20 +3245,20 @@ got_funcs:
                         * i.e. terminated by a domain component
                         */
                        if ( flags & LDAP_DN_PEDANTIC ) {
                         * i.e. terminated by a domain component
                         */
                        if ( flags & LDAP_DN_PEDANTIC ) {
-                               LDAP_FREE( *str );
-                               *str = NULL;
-                               rc = LDAP_INVALID_DN_SYNTAX;
+                               LDAP_FREE( bv->bv_val );
+                               bv->bv_val = NULL;
+                               rc = LDAP_ENCODING_ERROR;
                                break;
                        }
 
                        for ( l = 0; iRDN >= 0 ; iRDN-- ) {
                                ber_len_t       rdnl;
                                break;
                        }
 
                        for ( l = 0; iRDN >= 0 ; iRDN-- ) {
                                ber_len_t       rdnl;
-                               LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+                               LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
                        
                        
-                               if ( rdn2ADstr( rdn, &( *str )[ l ], 
-                                               &rdnl, first ) ) {
-                                       LDAP_FREE( *str );
-                                       *str = NULL;
+                               if ( rdn2ADstr( rdn, &bv->bv_val[ l ], 
+                                               flags, &rdnl, first ) ) {
+                                       LDAP_FREE( bv->bv_val );
+                                       bv->bv_val = NULL;
                                        goto return_results;
                                }
                                if ( first ) {
                                        goto return_results;
                                }
                                if ( first ) {
@@ -3234,19 +3268,214 @@ got_funcs:
                        }
                }
 
                        }
                }
 
-               ( *str )[ len ] = '\0';
+               bv->bv_len = len;
+               bv->bv_val[ bv->bv_len ] = '\0';
 
                rc = LDAP_SUCCESS;
 
                rc = LDAP_SUCCESS;
-               break;
-       }
+       } break;
 
        default:
 
        default:
-               assert( 0 );
-
+               return LDAP_PARAM_ERROR;
        }
 
        }
 
-       Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );
+#ifdef NEW_LOGGING
+       LDAP_LOG (( "getdn", LDAP_LEVEL_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 );
 }
 
 return_results:;
        return( rc );
 }
 
+#ifdef HAVE_TLS
+#include <openssl/x509.h>
+#include <openssl/err.h>
+
+/* 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 */
+