]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/dn.c
ITS5282 fix for 2.3
[openldap] / servers / slapd / dn.c
index 388ea12366907c731c54b2dcb023db20297ec439..832eae60d48942e064a314eeceffb76335df2e11 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2004 The OpenLDAP Foundation.
+ * Copyright 1998-2007 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,6 @@
 #include <ac/time.h>
 
 #include "slap.h"
-#include "ldap_pvt.h" /* must be after slap.h, to get ldap_bv2dn_x() & co */
 #include "lutil.h"
 
 /*
@@ -60,21 +59,26 @@ LDAPRDN_validate( LDAPRDN rdn )
        int             iAVA;
        int             rc;
 
-       assert( rdn );
+       assert( rdn != NULL );
 
        for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
                LDAPAVA                 *ava = rdn[ iAVA ];
                AttributeDescription    *ad;
                slap_syntax_validate_func *validate = NULL;
 
-               assert( ava );
+               assert( ava != NULL );
                
                if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
                        const char      *text = NULL;
 
                        rc = slap_bv2ad( &ava->la_attr, &ad, &text );
                        if ( rc != LDAP_SUCCESS ) {
-                               return LDAP_INVALID_SYNTAX;
+                               rc = slap_bv2undef_ad( &ava->la_attr,
+                                       &ad, &text,
+                                       SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
+                               if ( rc != LDAP_SUCCESS ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
                        }
 
                        ava->la_private = ( void * )ad;
@@ -113,27 +117,32 @@ LDAPDN_validate( LDAPDN dn )
        int             iRDN;
        int             rc;
 
-       assert( dn );
+       assert( dn != NULL );
 
        for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
                LDAPRDN         rdn = dn[ iRDN ];
                int             iAVA;
 
-               assert( rdn );
+               assert( rdn != NULL );
 
                for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
                        LDAPAVA                 *ava = rdn[ iAVA ];
                        AttributeDescription    *ad;
                        slap_syntax_validate_func *validate = NULL;
 
-                       assert( ava );
+                       assert( ava != NULL );
                        
                        if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
                                const char      *text = NULL;
 
                                rc = slap_bv2ad( &ava->la_attr, &ad, &text );
                                if ( rc != LDAP_SUCCESS ) {
-                                       return LDAP_INVALID_SYNTAX;
+                                       rc = slap_bv2undef_ad( &ava->la_attr,
+                                               &ad, &text,
+                                               SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
+                                       if ( rc != LDAP_SUCCESS ) {
+                                               return LDAP_INVALID_SYNTAX;
+                                       }
                                }
 
                                ava->la_private = ( void * )ad;
@@ -174,7 +183,7 @@ dnValidate(
        int             rc;
        LDAPDN          dn = NULL;
 
-       assert( in );
+       assert( in != NULL );
 
        if ( in->bv_len == 0 ) {
                return LDAP_SUCCESS;
@@ -212,7 +221,7 @@ rdnValidate(
        LDAPRDN         rdn;
        char*           p;
 
-       assert( in );
+       assert( in != NULL );
        if ( in->bv_len == 0 ) {
                return LDAP_SUCCESS;
 
@@ -253,81 +262,62 @@ rdnValidate(
  * Note: the sorting can be slightly improved by sorting first
  * by attribute type length, then by alphabetical order.
  *
- * uses a linear search; should be fine since the number of AVAs in
+ * uses an insertion sort; should be fine since the number of AVAs in
  * a RDN should be limited.
  */
-static void
-AVA_Sort( LDAPRDN rdn, int iAVA )
+static int
+AVA_Sort( LDAPRDN rdn, int nAVAs )
 {
+       LDAPAVA *ava_i;
        int             i;
-       LDAPAVA         *ava_in = rdn[ iAVA ];
 
-       assert( rdn );
-       assert( ava_in );
-       
-       for ( i = 0; i < iAVA; i++ ) {
-               LDAPAVA         *ava = rdn[ i ];
-               int             a, j;
+       assert( rdn != NULL );
 
-               assert( ava );
+       for ( i = 1; i < nAVAs; i++ ) {
+               LDAPAVA *ava_j;
+               int j;
 
-               a = strcmp( ava_in->la_attr.bv_val, ava->la_attr.bv_val );
+               ava_i = rdn[ i ];
+               for ( j = i-1; j >=0; j-- ) {
+                       int a;
 
-               if ( a > 0 ) {
-                       break;
-               }
+                       ava_j = rdn[ j ];
+                       a = strcmp( ava_i->la_attr.bv_val, ava_j->la_attr.bv_val );
 
-               while ( a == 0 ) {
-                       int             v, d;
+                       if ( a == 0 ) {
+                               int             d;
 
-                       d = ava_in->la_value.bv_len - ava->la_value.bv_len;
+                               d = ava_i->la_value.bv_len - ava_j->la_value.bv_len;
 
-                       v = memcmp( ava_in->la_value.bv_val, 
-                                       ava->la_value.bv_val,
-                                       d <= 0 ? ava_in->la_value.bv_len 
-                                               : ava->la_value.bv_len );
+                               a = memcmp( ava_i->la_value.bv_val, 
+                                               ava_j->la_value.bv_val,
+                                               d <= 0 ? ava_i->la_value.bv_len 
+                                                       : ava_j->la_value.bv_len );
 
-                       if ( v == 0 && d != 0 ) {
-                               v = d;
+                               if ( a == 0 ) {
+                                       a = d;
+                               }
                        }
+                       /* Duplicates are not allowed */
+                       if ( a == 0 )
+                               return LDAP_INVALID_DN_SYNTAX;
 
-                       if ( v <= 0 ) {
-                               /* 
-                                * got it!
-                                */
+                       if ( a > 0 )
                                break;
-                       }
-
-                       if ( ++i == iAVA ) {
-                               /*
-                                * already sorted
-                                */
-                               return;
-                       }
 
-                       ava = rdn[ i ];
-                       a = strcmp( ava_in->la_attr.bv_val, 
-                                       ava->la_attr.bv_val );
-               }
-
-               /*
-                * move ahead
-                */
-               for ( j = iAVA; j > i; j-- ) {
-                       rdn[ j ] = rdn[ j - 1 ];
+                       rdn[ j+1 ] = rdn[ j ];
                }
-               rdn[ i ] = ava_in;
-
-               return;
+               rdn[ j+1 ] = ava_i;
        }
+       return LDAP_SUCCESS;
 }
 
 static int
 LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
 {
 
-       int rc;
-       int             iAVA;
+       int rc, iAVA, do_sort = 0;
+
        for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
                LDAPAVA                 *ava = rdn[ iAVA ];
                AttributeDescription    *ad;
@@ -336,16 +326,20 @@ LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
                slap_syntax_transform_func *transf = NULL;
                MatchingRule *mr = NULL;
                struct berval           bv = BER_BVNULL;
-               int                     do_sort = 0;
 
-               assert( ava );
+               assert( ava != NULL );
 
                if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
                        const char      *text = NULL;
 
                        rc = slap_bv2ad( &ava->la_attr, &ad, &text );
                        if ( rc != LDAP_SUCCESS ) {
-                               return LDAP_INVALID_SYNTAX;
+                               rc = slap_bv2undef_ad( &ava->la_attr,
+                                       &ad, &text,
+                                       SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
+                               if ( rc != LDAP_SUCCESS ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
                        }
                        
                        ava->la_private = ( void * )ad;
@@ -372,7 +366,9 @@ LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
                } else { /* normalization */
                        validf = ad->ad_type->sat_syntax->ssyn_validate;
                        mr = ad->ad_type->sat_equality;
-                       if( mr ) normf = mr->smr_normalize;
+                       if( mr && (!( mr->smr_usage & SLAP_MR_MUTATION_NORMALIZER ))) {
+                               normf = mr->smr_normalize;
+                       }
                }
 
                if ( validf ) {
@@ -429,10 +425,14 @@ LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
                        ava->la_value = bv;
                        ava->la_flags |= LDAP_AVA_FREE_VALUE;
                }
+       }
+       rc = LDAP_SUCCESS;
 
-               if( do_sort ) AVA_Sort( rdn, iAVA );
+       if ( do_sort ) {
+               rc = AVA_Sort( rdn, iAVA );
        }
-       return LDAP_SUCCESS;
+
+       return rc;
 }
 
 /*
@@ -442,16 +442,16 @@ LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
 static int
 LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
 {
-       int             iRDN;
+       int             iRDN, do_sort = 0;
        int             rc;
 
-       assert( dn );
+       assert( dn != NULL );
 
        for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
                LDAPRDN         rdn = dn[ iRDN ];
                int             iAVA;
 
-               assert( rdn );
+               assert( rdn != NULL );
 
                for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
                        LDAPAVA                 *ava = rdn[ iAVA ];
@@ -461,16 +461,20 @@ LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
                        slap_syntax_transform_func *transf = NULL;
                        MatchingRule *mr = NULL;
                        struct berval           bv = BER_BVNULL;
-                       int                     do_sort = 0;
 
-                       assert( ava );
+                       assert( ava != NULL );
 
                        if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
                                const char      *text = NULL;
 
                                rc = slap_bv2ad( &ava->la_attr, &ad, &text );
                                if ( rc != LDAP_SUCCESS ) {
-                                       return LDAP_INVALID_SYNTAX;
+                                       rc = slap_bv2undef_ad( &ava->la_attr,
+                                               &ad, &text,
+                                               SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
+                                       if ( rc != LDAP_SUCCESS ) {
+                                               return LDAP_INVALID_SYNTAX;
+                                       }
                                }
                                
                                ava->la_private = ( void * )ad;
@@ -497,7 +501,9 @@ LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
                        } else { /* normalization */
                                validf = ad->ad_type->sat_syntax->ssyn_validate;
                                mr = ad->ad_type->sat_equality;
-                               if( mr ) normf = mr->smr_normalize;
+                               if( mr && (!( mr->smr_usage & SLAP_MR_MUTATION_NORMALIZER ))) {
+                                       normf = mr->smr_normalize;
+                               }
                        }
 
                        if ( validf ) {
@@ -555,10 +561,13 @@ LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
                                ava->la_flags |= LDAP_AVA_FREE_VALUE;
                        }
 
-                       if( do_sort ) AVA_Sort( rdn, iAVA );
+               }
+               if( do_sort ) {
+                       rc = AVA_Sort( rdn, iAVA );
+                       if ( rc != LDAP_SUCCESS )
+                               return rc;
                }
        }
-
        return LDAP_SUCCESS;
 }
 
@@ -571,8 +580,8 @@ dnNormalize(
     struct berval *out,
     void *ctx)
 {
-       assert( val );
-       assert( out );
+       assert( val != NULL );
+       assert( out != NULL );
 
        Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
 
@@ -627,8 +636,8 @@ rdnNormalize(
     struct berval *out,
     void *ctx)
 {
-       assert( val );
-       assert( out );
+       assert( val != NULL );
+       assert( out != NULL );
 
        Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
        if ( val->bv_len != 0 ) {
@@ -683,14 +692,10 @@ dnPretty(
        struct berval *out,
        void *ctx)
 {
-       assert( val );
-       assert( out );
+       assert( val != NULL );
+       assert( out != NULL );
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( OPERATION, ARGS, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
-#else
        Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
-#endif
 
        if ( val->bv_len == 0 ) {
                ber_dupbv_x( out, val, ctx );
@@ -732,11 +737,7 @@ dnPretty(
                }
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( OPERATION, ARGS, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
-#else
        Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
-#endif
 
        return LDAP_SUCCESS;
 }
@@ -748,14 +749,10 @@ rdnPretty(
        struct berval *out,
        void *ctx)
 {
-       assert( val );
-       assert( out );
+       assert( val != NULL );
+       assert( out != NULL );
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( OPERATION, ARGS, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
-#else
        Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
-#endif
 
        if ( val->bv_len == 0 ) {
                ber_dupbv_x( out, val, ctx );
@@ -799,11 +796,7 @@ rdnPretty(
                }
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( OPERATION, ARGS, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
-#else
        Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
-#endif
 
        return LDAP_SUCCESS;
 }
@@ -817,18 +810,12 @@ dnPrettyNormalDN(
        int flags,
        void *ctx )
 {
-       assert( val );
-       assert( dn );
+       assert( val != NULL );
+       assert( dn != NULL );
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( OPERATION, ARGS, ">>> dn%sDN: <%s>\n", 
-                       flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
-                       val->bv_val, 0 );
-#else
        Debug( LDAP_DEBUG_TRACE, ">>> dn%sDN: <%s>\n", 
                        flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
                        val->bv_val, 0 );
-#endif
 
        if ( val->bv_len == 0 ) {
                return LDAP_SUCCESS;
@@ -875,15 +862,11 @@ dnPrettyNormal(
        struct berval *normal,
        void *ctx)
 {
-#ifdef NEW_LOGGING
-       LDAP_LOG ( OPERATION, ENTRY, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 );
-#else
        Debug( LDAP_DEBUG_TRACE, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 );
-#endif
 
-       assert( val );
-       assert( pretty );
-       assert( normal );
+       assert( val != NULL );
+       assert( pretty != NULL );
+       assert( normal != NULL );
 
        if ( val->bv_len == 0 ) {
                ber_dupbv_x( pretty, val, ctx );
@@ -946,13 +929,8 @@ dnPrettyNormal(
                }
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG (OPERATION, RESULTS, "<<< dnPrettyNormal: <%s>, <%s>\n",
-               pretty->bv_val, normal->bv_val, 0  );
-#else
        Debug( LDAP_DEBUG_TRACE, "<<< dnPrettyNormal: <%s>, <%s>\n",
                pretty->bv_val, normal->bv_val, 0 );
-#endif
 
        return LDAP_SUCCESS;
 }
@@ -972,9 +950,9 @@ dnMatch(
        int match;
        struct berval *asserted = (struct berval *) assertedValue;
 
-       assert( matchp );
-       assert( value );
-       assert( assertedValue );
+       assert( matchp != NULL );
+       assert( value != NULL );
+       assert( assertedValue != NULL );
        assert( !BER_BVISNULL( value ) );
        assert( !BER_BVISNULL( asserted ) );
        
@@ -985,16 +963,113 @@ dnMatch(
                                value->bv_len );
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( CONFIG, ENTRY, "dnMatch: %d\n    %s\n    %s\n", 
-               match, value->bv_val, asserted->bv_val  );
-#else
        Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
                match, value->bv_val, asserted->bv_val );
-#endif
 
        *matchp = match;
-       return( LDAP_SUCCESS );
+       return LDAP_SUCCESS;
+}
+
+/*
+ * dnRelativeMatch routine
+ */
+int
+dnRelativeMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match;
+       struct berval *asserted = (struct berval *) assertedValue;
+
+       assert( matchp != NULL );
+       assert( value != NULL );
+       assert( assertedValue != NULL );
+       assert( !BER_BVISNULL( value ) );
+       assert( !BER_BVISNULL( asserted ) );
+
+       if( mr == slap_schema.si_mr_dnSubtreeMatch ) {
+               if( asserted->bv_len > value->bv_len ) {
+                       match = -1;
+               } else if ( asserted->bv_len == value->bv_len ) {
+                       match = memcmp( value->bv_val, asserted->bv_val, 
+                               value->bv_len );
+               } else {
+                       if( DN_SEPARATOR(
+                               value->bv_val[value->bv_len - asserted->bv_len - 1] ))
+                       {
+                               match = memcmp(
+                                       &value->bv_val[value->bv_len - asserted->bv_len],
+                                       asserted->bv_val, 
+                                       asserted->bv_len );
+                       } else {
+                               match = 1;
+                       }
+               }
+
+               *matchp = match;
+               return LDAP_SUCCESS;
+       }
+
+       if( mr == slap_schema.si_mr_dnSuperiorMatch ) {
+               asserted = value;
+               value = (struct berval *) assertedValue;
+               mr = slap_schema.si_mr_dnSubordinateMatch;
+       }
+
+       if( mr == slap_schema.si_mr_dnSubordinateMatch ) {
+               if( asserted->bv_len >= value->bv_len ) {
+                       match = -1;
+               } else {
+                       if( DN_SEPARATOR(
+                               value->bv_val[value->bv_len - asserted->bv_len - 1] ))
+                       {
+                               match = memcmp(
+                                       &value->bv_val[value->bv_len - asserted->bv_len],
+                                       asserted->bv_val, 
+                                       asserted->bv_len );
+                       } else {
+                               match = 1;
+                       }
+               }
+
+               *matchp = match;
+               return LDAP_SUCCESS;
+       }
+
+       if( mr == slap_schema.si_mr_dnOneLevelMatch ) {
+               if( asserted->bv_len >= value->bv_len ) {
+                       match = -1;
+               } else {
+                       if( DN_SEPARATOR(
+                               value->bv_val[value->bv_len - asserted->bv_len - 1] ))
+                       {
+                               match = memcmp(
+                                       &value->bv_val[value->bv_len - asserted->bv_len],
+                                       asserted->bv_val, 
+                                       asserted->bv_len );
+
+                               if( !match ) {
+                                       struct berval rdn;
+                                       rdn.bv_val = value->bv_val;
+                                       rdn.bv_len = value->bv_len - asserted->bv_len - 1;
+                                       match = dnIsOneLevelRDN( &rdn ) ? 0 : 1;
+                               }
+                       } else {
+                               match = 1;
+                       }
+               }
+
+               *matchp = match;
+               return LDAP_SUCCESS;
+       }
+
+       /* should not be reachable */
+       assert( 0 );
+       return LDAP_OTHER;
 }
 
 int
@@ -1009,9 +1084,9 @@ rdnMatch(
        int match;
        struct berval *asserted = (struct berval *) assertedValue;
 
-       assert( matchp );
-       assert( value );
-       assert( assertedValue );
+       assert( matchp != NULL );
+       assert( value != NULL );
+       assert( assertedValue != NULL );
        
        match = value->bv_len - asserted->bv_len;
 
@@ -1020,17 +1095,11 @@ rdnMatch(
                                value->bv_len );
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( CONFIG, ENTRY, "rdnMatch: %d\n    %s\n    %s\n", 
-               match, value->bv_val, asserted->bv_val  );
-#else
        Debug( LDAP_DEBUG_ARGS, "rdnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
                match, value->bv_val, asserted->bv_val );
-#endif
 
        *matchp = match;
-
-       return( LDAP_SUCCESS );
+       return LDAP_SUCCESS;
 }
 
 
@@ -1038,6 +1107,10 @@ rdnMatch(
  * dnParent - dn's parent, in-place
  * note: the incoming dn is assumed to be normalized/prettyfied,
  * so that escaped rdn/ava separators are in '\'+hexpair form
+ *
+ * note: "dn" and "pdn" can point to the same berval;
+ * beware that, in this case, the pointer to the original buffer
+ * will get lost.
  */
 void
 dnParent( 
@@ -1046,7 +1119,7 @@ dnParent(
 {
        char    *p;
 
-       p = strchr( dn->bv_val, ',' );
+       p = ber_bvchr( dn, ',' );
 
        /* one-level dn */
        if ( p == NULL ) {
@@ -1059,8 +1132,35 @@ dnParent(
        p++;
 
        assert( ATTR_LEADCHAR( p[ 0 ] ) );
-       pdn->bv_val = p;
        pdn->bv_len = dn->bv_len - (p - dn->bv_val);
+       pdn->bv_val = p;
+
+       return;
+}
+
+/*
+ * dnRdn - dn's rdn, in-place
+ * note: the incoming dn is assumed to be normalized/prettyfied,
+ * so that escaped rdn/ava separators are in '\'+hexpair form
+ */
+void
+dnRdn( 
+       struct berval   *dn, 
+       struct berval   *rdn )
+{
+       char    *p;
+
+       *rdn = *dn;
+       p = ber_bvchr( dn, ',' );
+
+       /* one-level dn */
+       if ( p == NULL ) {
+               return;
+       }
+
+       assert( DN_SEPARATOR( p[ 0 ] ) );
+       assert( ATTR_LEADCHAR( p[ 1 ] ) );
+       rdn->bv_len = p - dn->bv_val;
 
        return;
 }
@@ -1075,8 +1175,8 @@ dnExtractRdn(
        const char      *p;
        int             rc;
 
-       assert( dn );
-       assert( rdn );
+       assert( dn != NULL );
+       assert( rdn != NULL );
 
        if( dn->bv_len == 0 ) {
                return LDAP_OTHER;
@@ -1087,27 +1187,24 @@ dnExtractRdn(
                return rc;
        }
 
-       rc = ldap_rdn2bv_x( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
+       rc = ldap_rdn2bv_x( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY,
+               ctx );
 
        ldap_rdnfree_x( tmpRDN, ctx );
-       if ( rc != LDAP_SUCCESS ) {
-               return rc;
-       }
-
-       return LDAP_SUCCESS;
+       return rc;
 }
 
 /*
  * We can assume the input is a prettied or normalized DN
  */
-int 
+ber_len_t
 dn_rdnlen(
        Backend         *be,
        struct berval   *dn_in )
 {
        const char      *p;
 
-       assert( dn_in );
+       assert( dn_in != NULL );
 
        if ( dn_in == NULL ) {
                return 0;
@@ -1121,7 +1218,7 @@ dn_rdnlen(
                return 0;
        }
 
-       p = strchr( dn_in->bv_val, ',' );
+       p = ber_bvchr( dn_in, ',' );
 
        return p ? p - dn_in->bv_val : dn_in->bv_len;
 }
@@ -1145,7 +1242,7 @@ rdn_validate( struct berval *rdn )
        {
                return LDAP_INVALID_SYNTAX;
        }
-       return strchr( rdn->bv_val, ',' ) == NULL
+       return ber_bvchr( rdn, ',' ) == NULL
                ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
 
 #else
@@ -1215,7 +1312,7 @@ build_new_dn( struct berval * new_dn,
        new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
        new_dn->bv_val = (char *) slap_sl_malloc( new_dn->bv_len + 1, memctx );
 
-       ptr = lutil_strcopy( new_dn->bv_val, newrdn->bv_val );
+       ptr = lutil_strncopy( new_dn->bv_val, newrdn->bv_val, newrdn->bv_len );
        *ptr++ = ',';
        strcpy( ptr, parent_dn->bv_val );
 }
@@ -1232,8 +1329,8 @@ dnIsSuffix(
 {
        int     d = dn->bv_len - suffix->bv_len;
 
-       assert( dn );
-       assert( suffix );
+       assert( dn != NULL );
+       assert( suffix != NULL );
 
        /* empty suffix matches any dn */
        if ( suffix->bv_len == 0 ) {
@@ -1272,6 +1369,22 @@ dnIsOneLevelRDN( struct berval *rdn )
        return 1;
 }
 
+#ifdef HAVE_TLS
+static SLAP_CERT_MAP_FN *DNX509PeerNormalizeCertMap = NULL;
+#endif
+
+int register_certificate_map_function(SLAP_CERT_MAP_FN *fn)
+{
+#ifdef HAVE_TLS
+       if ( DNX509PeerNormalizeCertMap == NULL ) {
+               DNX509PeerNormalizeCertMap = fn;
+               return 0;
+       }
+#endif
+
+       return -1;
+}
+
 #ifdef HAVE_TLS
 /*
  * Convert an X.509 DN into a normalized LDAP DN
@@ -1283,7 +1396,8 @@ dnX509normalize( void *x509_name, struct berval *out )
        int rc = ldap_X509dn2bv( x509_name, out, LDAPDN_rewrite, 0 );
 
        Debug( LDAP_DEBUG_TRACE,
-               "dnX509Normalize: <%s>\n", out->bv_val, 0, 0 );
+               "dnX509Normalize: <%s> (%d)\n",
+               BER_BVISNULL( out ) ? "(null)" : out->bv_val, rc, 0 );
 
        return rc;
 }
@@ -1294,8 +1408,16 @@ dnX509normalize( void *x509_name, struct berval *out )
 int
 dnX509peerNormalize( void *ssl, struct berval *dn )
 {
+       int rc = LDAP_INVALID_CREDENTIALS;
+
+       if ( DNX509PeerNormalizeCertMap != NULL )
+               rc = (*DNX509PeerNormalizeCertMap)( ssl, dn );
 
-       return ldap_pvt_tls_get_peer_dn( ssl, dn,
-               (LDAPDN_rewrite_dummy *)LDAPDN_rewrite, 0 );
+       if ( rc != LDAP_SUCCESS ) {
+               rc = ldap_pvt_tls_get_peer_dn( ssl, dn,
+                       (LDAPDN_rewrite_dummy *)LDAPDN_rewrite, 0 );
+       }
+
+       return rc;
 }
 #endif