+static int
+LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
+{
+ int iRDN;
+ int rc;
+
+ assert( dn != NULL );
+
+ for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
+ LDAPRDN rdn = dn[ iRDN ];
+ int iAVA;
+
+ assert( rdn != NULL );
+
+ for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+ LDAPAVA *ava = rdn[ iAVA ];
+ AttributeDescription *ad;
+ slap_syntax_validate_func *validf = NULL;
+ slap_mr_normalize_func *normf = NULL;
+ slap_syntax_transform_func *transf = NULL;
+ MatchingRule *mr = NULL;
+ struct berval bv = BER_BVNULL;
+ int do_sort = 0;
+
+ 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 ) {
+ 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;
+ do_sort = 1;
+ }
+
+ /*
+ * Replace attr oid/name with the canonical name
+ */
+ ava->la_attr = ad->ad_cname;
+
+ if( ava->la_flags & LDAP_AVA_BINARY ) {
+ if( ava->la_value.bv_len == 0 ) {
+ /* BER encoding is empty */
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* AVA is binary encoded, don't muck with it */
+ } else if( flags & SLAP_LDAPDN_PRETTY ) {
+ transf = ad->ad_type->sat_syntax->ssyn_pretty;
+ if( !transf ) {
+ validf = ad->ad_type->sat_syntax->ssyn_validate;
+ }
+ } else { /* normalization */
+ validf = ad->ad_type->sat_syntax->ssyn_validate;
+ mr = ad->ad_type->sat_equality;
+ if( mr && (!( mr->smr_usage & SLAP_MR_MUTATION_NORMALIZER ))) {
+ normf = mr->smr_normalize;
+ }
+ }
+
+ if ( validf ) {
+ /* validate value before normalization */
+ rc = ( *validf )( ad->ad_type->sat_syntax,
+ ava->la_value.bv_len
+ ? &ava->la_value
+ : (struct berval *) &slap_empty_bv );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ if ( transf ) {
+ /*
+ * transform value by pretty function
+ * if value is empty, use empty_bv
+ */
+ rc = ( *transf )( ad->ad_type->sat_syntax,
+ ava->la_value.bv_len
+ ? &ava->la_value
+ : (struct berval *) &slap_empty_bv,
+ &bv, ctx );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ if ( normf ) {
+ /*
+ * normalize value
+ * if value is empty, use empty_bv
+ */
+ rc = ( *normf )(
+ SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
+ ad->ad_type->sat_syntax,
+ mr,
+ ava->la_value.bv_len
+ ? &ava->la_value
+ : (struct berval *) &slap_empty_bv,
+ &bv, ctx );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+
+ if( bv.bv_val ) {
+ if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
+ ber_memfree_x( ava->la_value.bv_val, ctx );
+ ava->la_value = bv;
+ ava->la_flags |= LDAP_AVA_FREE_VALUE;
+ }
+
+ if( do_sort ) AVA_Sort( rdn, iAVA );
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int
+dnNormalize(
+ slap_mask_t use,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *val,
+ struct berval *out,
+ void *ctx)
+{
+ assert( val != NULL );
+ assert( out != NULL );
+
+ Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
+
+ if ( val->bv_len != 0 ) {
+ LDAPDN dn = NULL;
+ int rc;
+
+ /*
+ * Go to structural representation
+ */
+ rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ assert( strlen( val->bv_val ) == val->bv_len );
+
+ /*
+ * Schema-aware rewrite
+ */
+ if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
+ ldap_dnfree_x( dn, ctx );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /*
+ * Back to string representation
+ */
+ rc = ldap_dn2bv_x( dn, out,
+ LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
+
+ ldap_dnfree_x( dn, ctx );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ } else {
+ ber_dupbv_x( out, val, ctx );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
+
+ return LDAP_SUCCESS;
+}