]> git.sur5r.net Git - openldap/commitdiff
mostly done...
authorPierangelo Masarati <ando@openldap.org>
Sun, 11 Jul 2004 22:57:51 +0000 (22:57 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sun, 11 Jul 2004 22:57:51 +0000 (22:57 +0000)
servers/slapd/overlays/rwm.c
servers/slapd/overlays/rwm.h
servers/slapd/overlays/rwmconf.c
servers/slapd/overlays/rwmdn.c
servers/slapd/overlays/rwmmap.c

index 5962963381553a7af75a34e0511db75c5206d863..16d9e9d9c14d1171752082505b9dcc6c36ec10a5 100644 (file)
@@ -31,7 +31,8 @@ rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie )
        struct ldaprwmap        *rwmap = 
                        (struct ldaprwmap *)on->on_bi.bi_private;
 
-       struct berval           dn, ndn, mdn = BER_BVNULL;
+       struct berval           dn = BER_BVNULL,
+                               ndn = BER_BVNULL;
        int                     rc = 0;
        dncookie                dc;
 
@@ -48,24 +49,15 @@ rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie )
        dc.normalized = 0;
 #endif
 
-       rc = rwm_dn_massage( &dc, &op->o_req_dn, &mdn );
+       rc = rwm_dn_massage( &dc, &op->o_req_dn, &dn, &ndn );
        if ( rc != LDAP_SUCCESS ) {
                return rc;
        }
 
-       if ( mdn.bv_val == op->o_req_dn.bv_val ) {
+       if ( dn.bv_val == op->o_req_dn.bv_val ) {
                return LDAP_SUCCESS;
        }
 
-       rc = dnPrettyNormal( NULL, &mdn, &dn, &ndn, op->o_tmpmemctx );
-       if ( rc != LDAP_SUCCESS ) {
-               return rc;
-       }
-
-       if ( mdn.bv_val != dn.bv_val ) {
-               ch_free( mdn.bv_val );
-       }
-
        op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
        op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
 
@@ -111,7 +103,7 @@ rwm_add( Operation *op, SlapReply *rs )
 
                rwm_map( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
                                &mapped, RWM_MAP );
-               if ( mapped.bv_val == NULL || mapped.bv_val[0] == '\0' ) {
+               if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
                        goto cleanup_attr;
                }
 
@@ -123,12 +115,10 @@ rwm_add( Operation *op, SlapReply *rs )
                         * the operation should give up, right?
                         */
 #ifdef ENABLE_REWRITE
-                       rc = rwm_dnattr_rewrite( op, rs, "addDn",
-                                       (*ap)->a_vals );
+                       rc = rwm_dnattr_rewrite( op, rs, "addDn", (*ap)->a_vals, NULL );
 #else
                        rc = 1;
-                       rc = rwm_dnattr_rewrite( op, rs, &rc,
-                                       (*ap)->a_vals );
+                       rc = rwm_dnattr_rewrite( op, rs, &rc, (*ap)->a_vals, NULL );
 #endif
                        if ( rc ) {
                                goto cleanup_attr;
@@ -143,12 +133,9 @@ cleanup_attr:;
                a = *ap;
 
                *ap = (*ap)->a_next;
-               ber_bvarray_free( a->a_vals );
-               ber_bvarray_free( a->a_nvals );
-               ch_free( a );
+               attr_free( a );
        }
 
-
        /* TODO: map attribute types, values of DN-valued attributes ... */
        return SLAP_CB_CONTINUE;
 }
@@ -162,6 +149,7 @@ rwm_bind( Operation *op, SlapReply *rs )
        int                     rc;
 
 #ifdef ENABLE_REWRITE
+       ( void )rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
        ( void )rewrite_session_init( rwmap->rwm_rw, op->o_conn );
 
        rc = rwm_op_dn_massage( op, rs, "bindDn" );
@@ -221,8 +209,7 @@ rwm_compare( Operation *op, SlapReply *rs )
        {
                rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
                                &mapped_vals[0], RWM_MAP );
-               if ( mapped_vals[0].bv_val == NULL
-                               || mapped_vals[0].bv_val[0] == '\0')
+               if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
                {
                        op->o_bd->bd_info = (BackendInfo *)on->on_info;
                        send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
@@ -235,12 +222,9 @@ rwm_compare( Operation *op, SlapReply *rs )
                mapped_at = op->orc_ava->aa_desc->ad_cname;
 
        } else {
-               rwm_map( &rwmap->rwm_at,
-                               &op->orc_ava->aa_desc->ad_cname,
-                               &mapped_at,
-                               RWM_MAP );
-               if ( mapped_at.bv_val == NULL 
-                               || mapped_at.bv_val[0] == '\0')
+               rwm_map( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
+                               &mapped_at, RWM_MAP );
+               if ( BER_BVISNULL( &mapped_at ) || BER_BVISEMPTY( &mapped_at ) )
                {
                        op->o_bd->bd_info = (BackendInfo *)on->on_info;
                        send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
@@ -249,7 +233,14 @@ rwm_compare( Operation *op, SlapReply *rs )
                if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
                {
                        mapped_vals[0] = op->orc_ava->aa_value;
-                       rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", mapped_vals );
+
+#ifdef ENABLE_REWRITE
+                       rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", mapped_vals, NULL );
+#else
+                       rc = 1;
+                       rc = rwm_dnattr_rewrite( op, rs, &rc, mapped_vals, NULL );
+#endif
+
                        if ( rc != LDAP_SUCCESS ) {
                                op->o_bd->bd_info = (BackendInfo *)on->on_info;
                                send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
@@ -263,7 +254,6 @@ rwm_compare( Operation *op, SlapReply *rs )
                }
        }
 
-       /* TODO: rewrite attribute types, values of DN-valued attributes ... */
        return SLAP_CB_CONTINUE;
 }
 
@@ -292,6 +282,11 @@ static int
 rwm_modify( Operation *op, SlapReply *rs )
 {
        slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
+       struct ldaprwmap        *rwmap = 
+                       (struct ldaprwmap *)on->on_bi.bi_private;
+
+       int                     isupdate;
+       Modifications           **mlp;
        int                     rc;
 
 #ifdef ENABLE_REWRITE
@@ -306,6 +301,120 @@ rwm_modify( Operation *op, SlapReply *rs )
                return rc;
        }
 
+       isupdate = be_shadow_update( op );
+       for ( mlp = &op->oq_modify.rs_modlist; *mlp; ) {
+               int             is_oc = 0;
+
+               if ( !isupdate && (*mlp)->sml_desc->ad_type->sat_no_user_mod  ) {
+                       Modifications   *ml;
+
+                       ml = *mlp;
+                       *mlp = (*mlp)->sml_next;
+                       slap_mod_free( &ml->sml_mod, 0 );
+                       free( ml );
+
+                       continue;
+               }
+
+               if ( (*mlp)->sml_desc == slap_schema.si_ad_objectClass 
+                               || (*mlp)->sml_desc == slap_schema.si_ad_structuralObjectClass ) {
+                       is_oc = 1;
+
+               } else {
+                       struct ldapmapping      *m;
+                       int                     drop_missing;
+
+                       drop_missing = rwm_mapping( &rwmap->rwm_at, &(*mlp)->sml_desc->ad_cname, &m, RWM_MAP );
+                       if ( drop_missing || ( m != NULL && BER_BVISNULL( &m->m_dst ) ) )
+                       {
+                               Modifications   *ml;
+
+                               ml = *mlp;
+                               *mlp = (*mlp)->sml_next;
+                               slap_mod_free( &ml->sml_mod, 0 );
+                               free( ml );
+
+                               continue;
+                       }
+
+                       if ( m ) {
+                               /* use new attribute description */
+                               assert( m->m_dst_ad );
+                               (*mlp)->sml_desc = m->m_dst_ad;
+                       }
+               }
+
+               if ( (*mlp)->sml_values != NULL ) {
+                       if ( is_oc ) {
+                               int     last, j;
+
+                               for ( last = 0; !BER_BVISNULL( &(*mlp)->sml_values[last] ); last++ )
+                                       /* count values */ ;
+                               last--;
+
+                               for ( j = 0; !BER_BVISNULL( &(*mlp)->sml_values[j] ); j++ ) {
+                                       struct berval   mapped = BER_BVNULL;
+
+                                       rwm_map( &rwmap->rwm_oc,
+                                                       &(*mlp)->sml_values[j],
+                                                       &mapped, RWM_MAP );
+                                       if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
+                                               /* FIXME: we allow to remove objectClasses as well;
+                                                * if the resulting entry is inconsistent, that's
+                                                * the relayed database's business...
+                                                */
+#if 0
+                                               Modifications   *ml;
+
+                                               ml = *mlp;
+                                               *mlp = (*mlp)->sml_next;
+                                               slap_mod_free( &ml->sml_mod, 0 );
+                                               free( ml );
+
+                                               continue;
+#endif
+                                               if ( last > j ) {
+                                                       (*mlp)->sml_values[j] = (*mlp)->sml_values[last];
+                                                       BER_BVZERO( &(*mlp)->sml_values[last] );
+                                               }
+                                               last--;
+
+                                       } else {
+                                               ch_free( (*mlp)->sml_values[j].bv_val );
+                                               ber_dupbv( &(*mlp)->sml_values[j], &mapped );
+                                       }
+                               }
+
+                       } else {
+                               if ( (*mlp)->sml_desc->ad_type->sat_syntax ==
+                                               slap_schema.si_syn_distinguishedName )
+                               {
+#ifdef ENABLE_REWRITE
+                                       rc = rwm_dnattr_rewrite( op, rs, "modifyDn",
+                                                       (*mlp)->sml_values, &(*mlp)->sml_nvalues );
+#else
+                                       rc = 1;
+                                       rc = rwm_dnattr_rewrite( op, rs, &rc, 
+                                                       (*mlp)->sml_values, &(*mlp)->sml_nvalues );
+#endif
+                               }
+
+                               if ( rc != LDAP_SUCCESS ) {
+                                       Modifications   *ml;
+
+                                       ml = *mlp;
+                                       *mlp = (*mlp)->sml_next;
+                                       slap_mod_free( &ml->sml_mod, 0 );
+                                       free( ml );
+
+                                       continue;
+                               }
+                       }
+               }
+
+               mlp = &(*mlp)->sml_next;
+       }
+
        /* TODO: rewrite attribute types, values of DN-valued attributes ... */
        return SLAP_CB_CONTINUE;
 }
@@ -332,11 +441,34 @@ rwm_modrdn( Operation *op, SlapReply *rs )
        return SLAP_CB_CONTINUE;
 }
 
+static int
+rwm_swap_attrs( Operation *op, SlapReply *rs )
+{
+       slap_callback   *cb = op->o_callback;
+       AttributeName   *an = (AttributeName *)cb->sc_private;
+
+       rs->sr_attrs = an;
+       
+       return SLAP_CB_CONTINUE;
+}
+
 static int
 rwm_search( Operation *op, SlapReply *rs )
 {
        slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
+       struct ldaprwmap        *rwmap = 
+                       (struct ldaprwmap *)on->on_bi.bi_private;
+
        int                     rc;
+       dncookie                dc;
+
+       struct berval           fstr = BER_BVNULL;
+       Filter                  *f = NULL;
+
+       slap_callback           *cb;
+       AttributeName           *an = NULL;
+
+       char                    *text = NULL;
 
 #ifdef ENABLE_REWRITE
        rc = rwm_op_dn_massage( op, rs, "searchDn" );
@@ -345,13 +477,89 @@ rwm_search( Operation *op, SlapReply *rs )
        rc = rwm_op_dn_massage( op, rs, &rc );
 #endif
        if ( rc != LDAP_SUCCESS ) {
-               op->o_bd->bd_info = (BackendInfo *)on->on_info;
-               send_ldap_error( op, rs, rc, "searchDn massage error" );
-               return rc;
+               text = "searchDn massage error";
+               goto error_return;
+       }
+
+       /*
+        * Rewrite the bind dn if needed
+        */
+       dc.rwmap = rwmap;
+#ifdef ENABLE_REWRITE
+       dc.conn = op->o_conn;
+       dc.rs = rs;
+       dc.ctx = "searchFilterAttrDN";
+#else
+       dc.tofrom = 0;
+       dc.normalized = 0;
+#endif
+
+       rc = rwm_filter_map_rewrite( &dc, op->ors_filter, &fstr );
+       if ( rc != LDAP_SUCCESS ) {
+               text = "searchFilter/searchFilterAttrDN massage error";
+               goto error_return;
+       }
+
+       f = str2filter_x( op, fstr.bv_val );
+
+       if ( f == NULL ) {
+               text = "massaged filter parse error";
+               goto error_return;
+       }
+
+       if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
+               ch_free( op->ors_filterstr.bv_val );
+       }
+
+       if( op->ors_filter ) {
+               filter_free_x( op, op->ors_filter );
+       }
+
+       op->ors_filter = f;
+       op->ors_filterstr = fstr;
+
+       rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
+                       op->ors_attrs, &an, RWM_MAP );
+       if ( rc != LDAP_SUCCESS ) {
+               text = "attribute list mapping error";
+               goto error_return;
        }
 
+       cb = (slap_callback *)ch_malloc( sizeof( slap_callback ) );
+       if ( cb == NULL ) {
+               rc = LDAP_NO_MEMORY;
+               goto error_return;
+       }
+
+       cb->sc_response = rwm_swap_attrs;
+       cb->sc_cleanup = NULL;
+       cb->sc_private = (void *)op->ors_attrs;
+       cb->sc_next = op->o_callback;
+
+       op->o_callback = cb;
+       op->ors_attrs = an;
+
        /* TODO: rewrite/map filter & attrs */
        return SLAP_CB_CONTINUE;
+
+error_return:;
+       if ( an != NULL ) {
+               ch_free( an );
+       }
+
+       if ( f != NULL ) {
+               filter_free_x( op, f );
+       }
+
+       if ( !BER_BVISNULL( &fstr ) ) {
+               ch_free( fstr.bv_val );
+       }
+
+       op->o_bd->bd_info = (BackendInfo *)on->on_info;
+       send_ldap_error( op, rs, rc, text );
+
+       return 1;
+
 }
 
 static int
@@ -385,6 +593,7 @@ rwm_matched( Operation *op, SlapReply *rs )
 
        struct berval           dn, mdn;
        dncookie                dc;
+       int                     rc;
 
        if ( rs->sr_matched == NULL ) {
                return SLAP_CB_CONTINUE;
@@ -400,11 +609,17 @@ rwm_matched( Operation *op, SlapReply *rs )
        dc.normalized = 0;
 #endif
        ber_str2bv( rs->sr_matched, 0, 0, &dn );
-       rwm_dn_massage( &dc, &dn, &mdn );
+       rc = rwm_dn_massage( &dc, &dn, &mdn, NULL );
+       if ( rc != LDAP_SUCCESS ) {
+               rs->sr_err = rc;
+               rs->sr_text = "Rewrite error";
+               return 1;
+       }
 
        if ( mdn.bv_val != dn.bv_val ) {
                if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
                        ch_free( (void *)rs->sr_matched );
+
                } else {
                        rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
                }
@@ -422,9 +637,11 @@ rwm_send_entry( Operation *op, SlapReply *rs )
                        (struct ldaprwmap *)on->on_bi.bi_private;
 
        Entry           *e = NULL;
-       struct berval   dn = BER_BVNULL, ndn = BER_BVNULL;
+       struct berval   dn = BER_BVNULL,
+                       ndn = BER_BVNULL;
        dncookie        dc;
-       int             rc = SLAP_CB_CONTINUE;
+       int             rc;
+       Attribute       **ap;
 
        assert( rs->sr_entry );
 
@@ -442,12 +659,20 @@ rwm_send_entry( Operation *op, SlapReply *rs )
        dc.tofrom = 0;
        dc.normalized = 0;
 #endif
-       if ( rwm_dn_massage( &dc, &e->e_name, &dn ) ) {
-               return LDAP_OTHER;
-       }
 
-       if ( e->e_name.bv_val == dn.bv_val ) {
-               return SLAP_CB_CONTINUE;
+       if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
+               /* FIXME: all we need to duplicate are:
+                * - dn
+                * - ndn
+                * - attributes that are requested
+                * - no values if attrsonly is set
+                */
+               e = entry_dup( e );
+               if ( e == NULL ) {
+                       rc = LDAP_NO_MEMORY;
+                       goto fail;
+               }
+               rs->sr_flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
        }
 
        /*
@@ -455,44 +680,165 @@ rwm_send_entry( Operation *op, SlapReply *rs )
         * from the one known to the meta, and a DN with unknown
         * attributes is returned.
         */
-       if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ) != LDAP_SUCCESS ) {
-               if ( dn.bv_val != e->e_name.bv_val ) {
-                       ch_free( dn.bv_val );
-               }
-               rc = LDAP_INVALID_DN_SYNTAX;
+       rc = rwm_dn_massage( &dc, &e->e_name, &dn, &ndn );
+       if ( rc != LDAP_SUCCESS ) {
                goto fail;
        }
 
-       if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
-               e = entry_dup( e );
-               if ( e == NULL ) {
-                       goto fail;
-               }
-               rs->sr_flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
+       if ( e->e_name.bv_val != dn.bv_val ) {
+               free( e->e_name.bv_val );
+               free( e->e_nname.bv_val );
+
+               e->e_name = dn;
+               e->e_nname = ndn;
        }
 
-       free( e->e_name.bv_val );
-       free( e->e_nname.bv_val );
+       /* TODO: map entry attribute types, objectclasses 
+        * and dn-valued attribute values */
+
+       /* FIXME: the entries are in the remote mapping form;
+        * so we need to select those attributes we are willing
+        * to return, and remap them accordingly */
+
+       for ( ap = &e->e_attrs; *ap; ) {
+               struct ldapmapping      *m;
+               int                     drop_missing;
+               int                     last;
+
+               if ( op->ors_attrs != NULL && !ad_inlist( (*ap)->a_desc, op->ors_attrs ) ) {
+                       Attribute       *a;
+
+                       a = *ap;
+                       *ap = (*ap)->a_next;
+
+                       attr_free( a );
+                       continue;
+               }
+
+               drop_missing = rwm_mapping( &rwmap->rwm_at,
+                               &(*ap)->a_desc->ad_cname, &m, RWM_REMAP );
+               if ( drop_missing || ( m != NULL && BER_BVISEMPTY( &m->m_dst ) ) ) {
+                       Attribute       *a;
+
+                       a = *ap;
+                       *ap = (*ap)->a_next;
+
+                       attr_free( a );
+                       continue;
+               }
+
+               /* no subschemaSubentry */
+               if ( (*ap)->a_desc == slap_schema.si_ad_subschemaSubentry ) {
+
+                       /* 
+                        * We eat target's subschemaSubentry because
+                        * a search for this value is likely not
+                        * to resolve to the appropriate backend;
+                        * later, the local subschemaSubentry is
+                        * added.
+                        */
+                       Attribute       *a;
+
+                       a = *ap;
+                       *ap = (*ap)->a_next;
+
+                       attr_free( a );
+                       continue;
+               }
+               
+               for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
+                       /* just count */ ;
+
+               if ( last == 0 ) {
+                       /* empty? for now, we leave it in place */
+                       goto next_attr;
+               }
+               last--;
+
+               if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
+                               || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
+               {
+                       struct berval   *bv;
+                       
+                       for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
+                               struct berval   mapped;
+
+                               rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
+                               if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
+                                       ch_free( bv[0].bv_val );
+                                       BER_BVZERO( &bv[0] );
+                                       if ( &(*ap)->a_vals[last] > &bv[0] ) {
+                                               bv[0] = (*ap)->a_vals[last];
+                                               BER_BVZERO( &(*ap)->a_vals[last] );
+                                       }
+                                       last--;
+                                       bv--;
+
+                               } else if ( mapped.bv_val != bv[0].bv_val ) {
+                                       /*
+                                        * FIXME: after LBER_FREEing
+                                        * the value is replaced by
+                                        * ch_alloc'ed memory
+                                        */
+                                       free( bv[0].bv_val );
+                                       ber_dupbv( &bv[0], &mapped );
+                               }
+                       }
+
+               /*
+                * It is necessary to try to rewrite attributes with
+                * dn syntax because they might be used in ACLs as
+                * members of groups; since ACLs are applied to the
+                * rewritten stuff, no dn-based subject clause could
+                * be used at the ldap backend side (see
+                * http://www.OpenLDAP.org/faq/data/cache/452.html)
+                * The problem can be overcome by moving the dn-based
+                * ACLs to the target directory server, and letting
+                * everything pass thru the ldap backend.
+                */
+               } else if ( (*ap)->a_desc->ad_type->sat_syntax ==
+                               slap_schema.si_syn_distinguishedName )
+               {
+                       rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
+                       if ( rc != LDAP_SUCCESS ) {
+                               Attribute       *a;
+
+                               a = *ap;
+                               *ap = (*ap)->a_next;
+
+                               attr_free( a );
+                               continue;
+                       }
+               }
+
+               if ( m != NULL ) {
+                       /* rewrite the attribute description */
+                       assert( m->m_dst_ad );
+                       (*ap)->a_desc = m->m_dst_ad;
+               }
+
+next_attr:;
+               ap = &(*ap)->a_next;
+       }
 
-       e->e_name = dn;
-       e->e_nname = ndn;
 
        rs->sr_entry = e;
 
-       /* TODO: map entry attribute types, objectclasses 
-        * and dn-valued attribute values */
-       
        return SLAP_CB_CONTINUE;
 
 fail:;
-       if ( dn.bv_val && ( dn.bv_val != e->e_name.bv_val ) ) {
+       if ( !BER_BVISNULL( &dn ) ) {
                ch_free( dn.bv_val );
        }
 
-       if ( ndn.bv_val ) {
+       if ( !BER_BVISNULL( &ndn ) ) {
                ch_free( ndn.bv_val );
        }
 
+       if ( e != NULL && e != rs->sr_entry ) {
+               entry_free( e );
+       }
+
        return rc;
 }
 
@@ -621,23 +967,32 @@ rwm_m_config(
 static int
 rwm_response( Operation *op, SlapReply *rs )
 {
-       int     rc;
+       int             rc;
 
        if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
                return rwm_send_entry( op, rs );
        }
 
        switch( op->o_tag ) {
+       case LDAP_REQ_SEARCH:
+               /* Note: the operation attrs are remapped */
+               if ( op->ors_attrs != NULL && op->ors_attrs != rs->sr_attrs )
+               {
+                       ch_free( op->ors_attrs );
+                       op->ors_attrs = rs->sr_attrs;
+               }
+               /* fall thru */
+
        case LDAP_REQ_BIND:
        case LDAP_REQ_ADD:
        case LDAP_REQ_DELETE:
        case LDAP_REQ_MODRDN:
        case LDAP_REQ_MODIFY:
        case LDAP_REQ_COMPARE:
-       case LDAP_REQ_SEARCH:
        case LDAP_REQ_EXTENDED:
                rc = rwm_matched( op, rs );
                break;
+
        default:
                rc = SLAP_CB_CONTINUE;
                break;
@@ -666,10 +1021,10 @@ rwm_config(
        if ( strncasecmp( argv[0], "rewrite", sizeof("rewrite") - 1 ) == 0 ) {
                rc = rwm_rw_config( be, fname, lineno, argc, argv );
 
-       } else if (strcasecmp( argv[0], "map" ) == 0 ) {
+       } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
                rc = rwm_m_config( be, fname, lineno, argc, argv );
 
-       } else if (strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
+       } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
                rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
 
        } else {
@@ -720,8 +1075,11 @@ rwm_over_init(
        
 #endif /* ENABLE_REWRITE */
 
-       rwm_map_init( &rwmap->rwm_oc, &mapping );
-       rwm_map_init( &rwmap->rwm_at, &mapping );
+       if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
+                       rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
+       {
+               return 1;
+       }
 
        on->on_bi.bi_private = (void *)rwmap;
 
index c3d2cc2745183bb576fad78fd328ea407f28396c..9d3cf31f418a59cdca7f441580bdd1497c5b6701 100644 (file)
@@ -93,32 +93,40 @@ typedef struct dncookie {
 #endif
 } dncookie;
 
-int rwm_dn_massage(dncookie *dc, struct berval *dn, struct berval *res);
+int rwm_dn_massage( dncookie *dc, struct berval *in,
+       struct berval *dn, struct berval *ndn );
 
 /* attributeType/objectClass mapping */
 int rwm_mapping_cmp (const void *, const void *);
 int rwm_mapping_dup (void *, void *);
 
-void rwm_map_init ( struct ldapmap *lm, struct ldapmapping ** );
+int rwm_map_init ( struct ldapmap *lm, struct ldapmapping ** );
 void rwm_map ( struct ldapmap *map, struct berval *s, struct berval *m,
        int remap );
+int rwm_mapping ( struct ldapmap *map, struct berval *s,
+               struct ldapmapping **m, int remap );
 #define RWM_MAP        0
 #define RWM_REMAP      1
 char *
 rwm_map_filter(
                struct ldapmap *at_map,
                struct ldapmap *oc_map,
-               struct berval *f,
-               int remap
-);
+               struct berval *f );
 
 int
 rwm_map_attrs(
                struct ldapmap *at_map,
                AttributeName *a,
                int remap,
-               char ***mapped_attrs
-);
+               char ***mapped_attrs );
+
+int
+rwm_map_attrnames(
+               struct ldapmap *at_map,
+               struct ldapmap *oc_map,
+               AttributeName *an,
+               AttributeName **anp,
+               int remap );
 
 extern void rwm_mapping_free ( void *mapping );
 
@@ -134,8 +142,7 @@ extern int
 rwm_filter_map_rewrite(
                dncookie                *dc,
                Filter                  *f,
-               struct berval           *fstr,
-               int                     remap );
+               struct berval           *fstr );
 
 /* suffix massaging by means of librewrite */
 #ifdef ENABLE_REWRITE
@@ -147,8 +154,8 @@ extern int rwm_dnattr_rewrite(
        Operation               *op,
        SlapReply               *rs,
        void                    *cookie,
-       BerVarray               a_vals
-       );
+       BerVarray               a_vals,
+       BerVarray               *pa_nvals );
 extern int rwm_dnattr_result_rewrite( dncookie *dc, BerVarray a_vals );
 
 LDAP_END_DECL
index 4bc782e88c7daf78ef120d44aafc2752a4274718..7917882ad93a38aaf31a6f0fe976ebdbb255b9f7 100644 (file)
@@ -172,10 +172,15 @@ rwm_map_config(
                                 * and add it here.
                                 */
 
-                               mapping[0].m_src_ad = ch_malloc( sizeof( AttributeDescription ) );
-                               memset( mapping[0].m_src_ad, 0, sizeof( AttributeDescription ) );
-                               mapping[0].m_src_ad->ad_cname = mapping[0].m_src;
-                               mapping[1].m_flags |= RWMMAP_F_FREE_SRC;
+                               rc = slap_bv2undef_ad( &mapping[0].m_src,
+                                               &mapping[0].m_src_ad, &text );
+                               if ( rc != LDAP_SUCCESS ) {
+                                       fprintf( stderr,
+       "%s: line %d: source attributeType '%s': %d (%s)\n",
+                                               fname, lineno, src, rc, text ? text : "null" );
+                                       return 1;
+                               }
+
                        }
                        mapping[1].m_dst_ad = mapping[0].m_src_ad;
                }
@@ -187,15 +192,19 @@ rwm_map_config(
        "is not defined in schema\n",
                                fname, lineno, dst );
 
-                       mapping[0].m_dst_ad = ch_malloc( sizeof( AttributeDescription ) );
-                       memset( mapping[0].m_dst_ad, 0, sizeof( AttributeDescription ) );
-                       mapping[0].m_dst_ad->ad_cname = mapping[0].m_dst;
-                       mapping[1].m_flags |= RWMMAP_F_FREE_SRC;
+                       rc = slap_bv2undef_ad( &mapping[0].m_dst,
+                                       &mapping[0].m_dst_ad, &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               fprintf( stderr,
+       "%s: line %d: destination attributeType '%s': %d (%s)\n",
+                                       fname, lineno, src, rc, text ? text : "null" );
+                               return 1;
+                       }
                }
                mapping[1].m_src_ad = mapping[0].m_dst_ad;
        }
 
-       if ( (src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL)
+       if ( ( src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL)
                        || avl_find( map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp ) != NULL)
        {
                fprintf( stderr,
index e5f31160e0aa61206f92be3d38527cb46789abab..85c929b2c31ba9a8953aebf2cd77b33848001d1e 100644 (file)
 int
 rwm_dn_massage(
        dncookie *dc,
+       struct berval *in,
        struct berval *dn,
-       struct berval *res
+       struct berval *ndn
 )
 {
-       int rc = 0;
+       int             rc = 0;
+       struct berval   mdn;
 
        rc = rewrite_session( dc->rwmap->rwm_rw, dc->ctx,
-                       ( dn->bv_len ? dn->bv_val : "" ), 
-                       dc->conn, &res->bv_val );
+                       ( in->bv_len ? in->bv_val : "" ), 
+                       dc->conn, &mdn.bv_val );
        switch ( rc ) {
        case REWRITE_REGEXEC_OK:
-               if ( res->bv_val != NULL ) {
-                       res->bv_len = strlen( res->bv_val );
+               if ( !BER_BVISNULL( &mdn ) ) {
+
+                       mdn.bv_len = strlen( mdn.bv_val );
+                       
+                       if ( dn != NULL && ndn != NULL ) {
+                               rc = dnPrettyNormal( NULL, &mdn, dn, ndn, NULL );
+
+                       } else if ( dn != NULL ) {
+                               rc = dnPretty( NULL, &mdn, dn, NULL );
+
+                       } else if ( ndn != NULL) {
+                               rc = dnNormalize( 0, NULL, NULL, &mdn, ndn, NULL );
+                       }
+
+                       if ( mdn.bv_val != in->bv_val ) {
+                               ch_free( mdn.bv_val );
+                       }
+
                } else {
-                       *res = *dn;
+                       /* we assume the input string is already in pretty form,
+                        * and that the normalized version is already available */
+                       *dn = *in;
+                       if ( ndn != NULL ) {
+                               BER_BVZERO( ndn );
+                       }
+                       rc = LDAP_SUCCESS;
                }
+
 #ifdef NEW_LOGGING
                LDAP_LOG( BACK_LDAP, DETAIL1, 
                        "[rw] %s: \"%s\" -> \"%s\"\n",
-                       dc->ctx, dn->bv_val, res->bv_val );             
+                       dc->ctx, in->bv_val, dn->bv_val );
 #else /* !NEW_LOGGING */
                Debug( LDAP_DEBUG_ARGS,
                        "[rw] %s: \"%s\" -> \"%s\"\n",
-                       dc->ctx, dn->bv_val, res->bv_val );             
+                       dc->ctx, in->bv_val, dn->bv_val );              
 #endif /* !NEW_LOGGING */
-               rc = LDAP_SUCCESS;
                break;
                
        case REWRITE_REGEXEC_UNWILLING:
@@ -97,48 +121,74 @@ rwm_dn_massage(
 int
 rwm_dn_massage(
        dncookie *dc,
-       struct berval *odn,
-       struct berval *res
+       struct berval *tmpin,
+       struct berval *dn,
+       struct berval *ndn
 )
 {
-       int     i, src, dst;
-       struct berval pretty = {0,NULL}, *dn = odn;
+       int             i, src, dst;
+       struct berval   pretty = BER_BVNULL,
+                       normal = BER_BVNULL,
+                       *in = tmpin;
 
-       assert( res );
+       assert( dn );
 
-       if ( dn == NULL ) {
-               res->bv_val = NULL;
-               res->bv_len = 0;
-               return 0;
+       if ( in == NULL || BER_BVISNULL( in ) ) {
+               dn->bv_val = NULL;
+               dn->bv_len = 0;
+               return LDAP_SUCCESS;
        }
        if ( dc->rwmap == NULL || dc->rwmap->rwm_suffix_massage == NULL ) {
-               *res = *dn;
-               return 0;
+               *dn = *in;
+               return LDAP_SUCCESS;
        }
 
        if ( dc->tofrom ) {
                src = 0 + dc->normalized;
                dst = 2 + dc->normalized;
+
        } else {
+               int     rc;
+
                src = 2 + dc->normalized;
                dst = 0 + dc->normalized;
+
                /* DN from remote server may be in arbitrary form.
                 * Pretty it so we can parse reliably.
                 */
-               dnPretty( NULL, dn, &pretty, NULL );
-               if (pretty.bv_val) dn = &pretty;
+               if ( dc->normalized && dn == NULL ) {
+                       rc = dnNormalize( 0, NULL, NULL, in, &normal, NULL );
+
+               } else if ( !dc->normalized && ndn == NULL ) {
+                       rc = dnPretty( NULL, in, &pretty, NULL );
+
+               } else {
+                       rc = dnPrettyNormal( NULL, in, &pretty, &normal, NULL );
+               }
+
+               if ( rc != LDAP_SUCCESS ) {
+                       return rc;
+               }
+
+               if ( dc->normalized && !BER_BVISNULL( &normal) ) {
+                       in = &normal;
+
+               } else if ( !dc->normalized && !BER_BVISNULL( &pretty ) ) {
+                       in = &pretty;
+               }
        }
 
        for ( i = 0;
                dc->rwmap->rwm_suffix_massage[i].bv_val != NULL;
                i += 4 ) {
                int aliasLength = dc->rwmap->rwm_suffix_massage[i+src].bv_len;
-               int diff = dn->bv_len - aliasLength;
+               int diff = in->bv_len - aliasLength;
 
                if ( diff < 0 ) {
                        /* alias is longer than dn */
                        continue;
-               } else if ( diff > 0 && ( !DN_SEPARATOR(dn->bv_val[diff-1]))) {
+
+               } else if ( diff > 0 && ( !DN_SEPARATOR(in->bv_val[diff-1]))) {
                        /* FIXME: DN_SEPARATOR() is intended to work
                         * on a normalized/pretty DN, so that ';'
                         * is never used as a DN separator */
@@ -146,34 +196,44 @@ rwm_dn_massage(
                        /* At a DN Separator */
                }
 
-               if ( !strcmp( dc->rwmap->rwm_suffix_massage[i+src].bv_val, &dn->bv_val[diff] ) ) {
-                       res->bv_len = diff + dc->rwmap->rwm_suffix_massage[i+dst].bv_len;
-                       res->bv_val = ch_malloc( res->bv_len + 1 );
-                       strncpy( res->bv_val, dn->bv_val, diff );
-                       strcpy( &res->bv_val[diff], dc->rwmap->rwm_suffix_massage[i+dst].bv_val );
+               if ( !strcmp( dc->rwmap->rwm_suffix_massage[i+src].bv_val, &in->bv_val[diff] ) ) {
+                       dn->bv_len = diff + dc->rwmap->rwm_suffix_massage[i+dst].bv_len;
+                       dn->bv_val = ch_malloc( dn->bv_len + 1 );
+                       strncpy( dn->bv_val, in->bv_val, diff );
+                       strcpy( &dn->bv_val[diff], dc->rwmap->rwm_suffix_massage[i+dst].bv_val );
 #ifdef NEW_LOGGING
                        LDAP_LOG ( BACK_LDAP, ARGS, 
                                "rwm_dn_massage: converted \"%s\" to \"%s\"\n",
-                               dn->bv_val, res->bv_val, 0 );
+                               in->bv_val, dn->bv_val, 0 );
 #else
                        Debug( LDAP_DEBUG_ARGS,
                                "rwm_dn_massage:"
                                " converted \"%s\" to \"%s\"\n",
-                               dn->bv_val, res->bv_val, 0 );
+                               in->bv_val, dn->bv_val, 0 );
 #endif
                        break;
                }
        }
-       if (pretty.bv_val) {
-               ch_free(pretty.bv_val);
-               dn = odn;
+
+       if ( !BER_BVISNULL( &pretty ) ) {
+               ch_free( pretty.bv_val );
+       }
+
+       if ( !BER_BVISNULL( &normal ) ) {
+               ch_free( normal.bv_val );
        }
+
+       in = tmpin;
+
        /* Nothing matched, just return the original DN */
-       if (res->bv_val == NULL) {
-               *res = *dn;
+       if ( dc->normalized && BER_BVISNULL( ndn ) ) {
+               *ndn = *in;
+
+       } else if ( !dc->normalized && BER_BVISNULL( dn ) ) {
+               *dn = *in;
        }
 
-       return 0;
+       return LDAP_SUCCESS;
 }
 #endif /* !ENABLE_REWRITE */
 
index c1f1d49d356263bc568d9dad1fcfff1d5cab1c0f..9d79679be31ccc694c49d70f784e5e74b5bb1e0b 100644 (file)
@@ -42,9 +42,11 @@ rwm_mapping_cmp( const void *c1, const void *c2 )
        struct ldapmapping *map1 = (struct ldapmapping *)c1;
        struct ldapmapping *map2 = (struct ldapmapping *)c2;
        int rc = map1->m_src.bv_len - map2->m_src.bv_len;
+       
        if ( rc ) {
                return rc;
        }
+
        return strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val );
 }
 
@@ -62,10 +64,12 @@ rwm_mapping_dup( void *c1, void *c2 )
        return ( ( strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val ) == 0 ) ? -1 : 0 );
 }
 
-void
+int
 rwm_map_init( struct ldapmap *lm, struct ldapmapping **m )
 {
-       struct ldapmapping *mapping;
+       struct ldapmapping      *mapping;
+       const char              *text;
+       int                     rc;
 
        assert( m );
 
@@ -77,9 +81,15 @@ rwm_map_init( struct ldapmap *lm, struct ldapmapping **m )
                return;
        }
 
-       ber_str2bv( "objectClass", sizeof("objectClass") - 1, 1,
-                       &mapping->m_src);
+       rc = slap_str2ad( "objectClass", &mapping->m_src_ad, &text );
+       if ( rc != LDAP_SUCCESS ) {
+               return rc;
+       }
+
+       mapping->m_dst_ad = mapping->m_src_ad;
+       ber_dupbv( &mapping->m_dst, &mapping->m_src_ad->ad_cname );
        ber_dupbv( &mapping->m_dst, &mapping->m_src );
+
        mapping[1].m_src = mapping->m_src;
        mapping[1].m_dst = mapping->m_dst;
 
@@ -87,28 +97,47 @@ rwm_map_init( struct ldapmap *lm, struct ldapmapping **m )
                        rwm_mapping_cmp, rwm_mapping_dup );
        avl_insert( &lm->remap, (caddr_t)&mapping[1], 
                        rwm_mapping_cmp, rwm_mapping_dup );
+
        *m = mapping;
+
+       return rc;
 }
 
-void
-rwm_map( struct ldapmap *map, struct berval *s, struct berval *bv, int remap )
+int
+rwm_mapping( struct ldapmap *map, struct berval *s, struct ldapmapping **m, int remap )
 {
        Avlnode *tree;
-       struct ldapmapping *mapping, fmapping;
+       struct ldapmapping fmapping;
 
-       if (remap == RWM_REMAP) {
+       assert( m );
+
+       if ( remap == RWM_REMAP ) {
                tree = map->remap;
+
        } else {
                tree = map->map;
        }
 
-       bv->bv_len = 0;
-       bv->bv_val = NULL;
        fmapping.m_src = *s;
-       mapping = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping,
+       *m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping,
                        rwm_mapping_cmp );
+
+       if ( *m == NULL ) {
+               return map->drop_missing;
+       }
+
+       return 0;
+}
+
+void
+rwm_map( struct ldapmap *map, struct berval *s, struct berval *bv, int remap )
+{
+       struct ldapmapping *mapping;
+
+       BER_BVZERO( bv );
+       rwm_mapping( map, s, &mapping, remap );
        if ( mapping != NULL ) {
-               if ( mapping->m_dst.bv_val ) {
+               if ( !BER_BVISNULL( &mapping->m_dst ) ) {
                        *bv = mapping->m_dst;
                }
                return;
@@ -117,8 +146,155 @@ rwm_map( struct ldapmap *map, struct berval *s, struct berval *bv, int remap )
        if ( !map->drop_missing ) {
                *bv = *s;
        }
+}
+
+/*
+ * Map attribute names in place
+ */
+int
+rwm_map_attrnames(
+               struct ldapmap *at_map,
+               struct ldapmap *oc_map,
+               AttributeName *an,
+               AttributeName **anp,
+               int remap
+)
+{
+       int             i, j;
+
+       if ( an == NULL ) {
+               return LDAP_SUCCESS;
+       }
+
+       for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
+               /* just count */ ;
+       *anp = ch_malloc( ( i + 1 )* sizeof( AttributeName ) );
+
+       for ( i = 0, j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
+               struct ldapmapping      *m;
+               int                     at_drop_missing = 0,
+                                       oc_drop_missing = 0;
+
+               if ( an[i].an_desc ) {
+                       if ( !at_map ) {
+                               /* FIXME: better leave as is? */
+                               continue;
+                       }
+                               
+                       at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
+                       if ( at_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
+                               continue;
+                       }
+
+                       if ( !m ) {
+                               (*anp)[j] = an[i];
+                               j++;
+                               continue;
+                       }
+
+                       (*anp)[j] = an[i];
+                       if ( remap == RWM_MAP ) {
+                               (*anp)[j].an_name = m->m_dst;
+                               (*anp)[j].an_desc = m->m_dst_ad;
+                       } else {
+                               (*anp)[j].an_name = m->m_src;
+                               (*anp)[j].an_desc = m->m_src_ad;
+
+                       }
+
+                       j++;
+                       continue;
+
+               } else if ( an[i].an_oc ) {
+                       if ( !oc_map ) {
+                               /* FIXME: better leave as is? */
+                               continue;
+                       }
+
+                       oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
+
+                       if ( oc_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
+                               continue;
+                       }
+
+                       if ( !m ) {
+                               (*anp)[j] = an[i];
+                               j++;
+                               continue;
+                       }
+
+                       (*anp)[j] = an[i];
+                       if ( remap == RWM_MAP ) {
+                               (*anp)[j].an_name = m->m_dst;
+                               (*anp)[j].an_oc = m->m_dst_oc;
+                       } else {
+                               (*anp)[j].an_name = m->m_src;
+                               (*anp)[j].an_oc = m->m_src_oc;
+                       }
+
+               } else {
+                       at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
+               
+                       if ( at_drop_missing || !m ) {
+
+                               oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
+
+                               /* if both at_map and oc_map required to drop missing,
+                                * then do it */
+                               if ( oc_drop_missing && at_drop_missing ) {
+                                       continue;
+                               }
+
+                               /* if no oc_map mapping was found and at_map required
+                                * to drop missing, then do it; otherwise, at_map wins
+                                * and an is considered an attr and is left unchanged */
+                               if ( !m ) {
+                                       if ( at_drop_missing ) {
+                                               continue;
+                                       }
+                                       (*anp)[j] = an[i];
+                                       j++;
+                                       continue;
+                               }
+       
+                               if ( BER_BVISNULL( &m->m_dst ) ) {
+                                       continue;
+                               }
+
+                               (*anp)[j] = an[i];
+                               if ( remap == RWM_MAP ) {
+                                       (*anp)[j].an_name = m->m_dst;
+                                       (*anp)[j].an_oc = m->m_dst_oc;
+                               } else {
+                                       (*anp)[j].an_name = m->m_src;
+                                       (*anp)[j].an_oc = m->m_src_oc;
+                               }
+                               j++;
+                               continue;
+                       }
+
+                       if ( !BER_BVISNULL( &m->m_dst ) ) {
+                               (*anp)[j] = an[i];
+                               if ( remap == RWM_MAP ) {
+                                       (*anp)[j].an_name = m->m_dst;
+                                       (*anp)[j].an_desc = m->m_dst_ad;
+                               } else {
+                                       (*anp)[j].an_name = m->m_src;
+                                       (*anp)[j].an_desc = m->m_src_ad;
+                               }
+                               j++;
+                               continue;
+                       }
+               }
+       }
+
+       if ( j == 0 && i != 0 ) {
+               memset( &(*anp)[0], 0, sizeof( AttributeName ) );
+               BER_BVSTR( &(*anp)[0].an_name, LDAP_NO_ATTRS );
+       }
+       memset( &(*anp)[j], 0, sizeof( AttributeName ) );
 
-       return;
+       return LDAP_SUCCESS;
 }
 
 int
@@ -131,14 +307,13 @@ rwm_map_attrs(
 {
        int i, j;
        char **na;
-       struct berval mapped;
 
        if ( an == NULL ) {
                *mapped_attrs = NULL;
                return LDAP_SUCCESS;
        }
 
-       for ( i = 0; an[i].an_name.bv_val; i++ ) {
+       for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
                /*  */
        }
 
@@ -148,10 +323,15 @@ rwm_map_attrs(
                return LDAP_NO_MEMORY;
        }
 
-       for ( i = j = 0; an[i].an_name.bv_val; i++ ) {
-               rwm_map( at_map, &an[i].an_name, &mapped, remap );
-               if ( mapped.bv_val != NULL && mapped.bv_val != '\0' ) {
-                       na[j++] = mapped.bv_val;
+       for ( i = j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
+               struct ldapmapping      *m;
+               
+               if ( rwm_mapping( at_map, &an[i].an_name, &m, remap ) ) {
+                       continue;
+               }
+
+               if ( !m || ( m && !BER_BVISNULL( &m->m_dst ) ) ) {
+                       na[j++] = m->m_dst.bv_val;
                }
        }
        if ( j == 0 && i != 0 ) {
@@ -176,14 +356,12 @@ map_attr_value(
        int                     freeval = 0;
 
        rwm_map( &dc->rwmap->rwm_at, &ad->ad_cname, mapped_attr, remap );
-       if ( mapped_attr->bv_val == NULL || mapped_attr->bv_val[0] == '\0') {
+       if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
                /*
                 * FIXME: are we sure we need to search oc_map if at_map fails?
                 */
-               rwm_map( &dc->rwmap->rwm_oc, &ad->ad_cname, mapped_attr,
-                               remap );
-               if ( mapped_attr->bv_val == NULL
-                               || mapped_attr->bv_val[0] == '\0' )
+               rwm_map( &dc->rwmap->rwm_oc, &ad->ad_cname, mapped_attr, remap );
+               if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) )
                {
                        *mapped_attr = ad->ad_cname;
                }
@@ -195,13 +373,15 @@ map_attr_value(
 
        if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
        {
-               dncookie fdc = *dc;
+               dncookie        fdc = *dc;
+               int             rc;
 
 #ifdef ENABLE_REWRITE
                fdc.ctx = "searchFilterAttrDN";
 #endif
 
-               switch ( rwm_dn_massage( &fdc, value, &vtmp ) ) {
+               rc = rwm_dn_massage( &fdc, value, &vtmp, NULL );
+               switch ( rc ) {
                case LDAP_SUCCESS:
                        if ( vtmp.bv_val != value->bv_val ) {
                                freeval = 1;
@@ -209,9 +389,8 @@ map_attr_value(
                        break;
                
                case LDAP_UNWILLING_TO_PERFORM:
-                       return -1;
-
                case LDAP_OTHER:
+               default:
                        return -1;
                }
 
@@ -219,7 +398,7 @@ map_attr_value(
                        || ad == slap_schema.si_ad_structuralObjectClass )
        {
                rwm_map( &dc->rwmap->rwm_oc, value, &vtmp, remap );
-               if ( vtmp.bv_val == NULL || vtmp.bv_val[0] == '\0' ) {
+               if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
                        vtmp = *value;
                }
                
@@ -240,8 +419,7 @@ static int
 rwm_int_filter_map_rewrite(
                dncookie                *dc,
                Filter                  *f,
-               struct berval           *fstr,
-               int                     remap )
+               struct berval           *fstr )
 {
        int             i;
        Filter          *p;
@@ -265,13 +443,12 @@ rwm_int_filter_map_rewrite(
        switch ( f->f_choice ) {
        case LDAP_FILTER_EQUALITY:
                if ( map_attr_value( dc, f->f_av_desc, &atmp,
-                                       &f->f_av_value, &vtmp, remap ) )
+                                       &f->f_av_value, &vtmp, RWM_MAP ) )
                {
                        return -1;
                }
 
-               fstr->bv_len = atmp.bv_len + vtmp.bv_len
-                       + ( sizeof( "(=)" ) - 1 );
+               fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(=)" );
                fstr->bv_val = malloc( fstr->bv_len + 1 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
@@ -282,13 +459,12 @@ rwm_int_filter_map_rewrite(
 
        case LDAP_FILTER_GE:
                if ( map_attr_value( dc, f->f_av_desc, &atmp,
-                                       &f->f_av_value, &vtmp, remap ) )
+                                       &f->f_av_value, &vtmp, RWM_MAP ) )
                {
                        return -1;
                }
 
-               fstr->bv_len = atmp.bv_len + vtmp.bv_len
-                       + ( sizeof( "(>=)" ) - 1 );
+               fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(>=)" );
                fstr->bv_val = malloc( fstr->bv_len + 1 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
@@ -299,13 +475,12 @@ rwm_int_filter_map_rewrite(
 
        case LDAP_FILTER_LE:
                if ( map_attr_value( dc, f->f_av_desc, &atmp,
-                                       &f->f_av_value, &vtmp, remap ) )
+                                       &f->f_av_value, &vtmp, RWM_MAP ) )
                {
                        return -1;
                }
 
-               fstr->bv_len = atmp.bv_len + vtmp.bv_len
-                       + ( sizeof( "(<=)" ) - 1 );
+               fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(<=)" );
                fstr->bv_val = malloc( fstr->bv_len + 1 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
@@ -316,13 +491,12 @@ rwm_int_filter_map_rewrite(
 
        case LDAP_FILTER_APPROX:
                if ( map_attr_value( dc, f->f_av_desc, &atmp,
-                                       &f->f_av_value, &vtmp, remap ) )
+                                       &f->f_av_value, &vtmp, RWM_MAP ) )
                {
                        return -1;
                }
 
-               fstr->bv_len = atmp.bv_len + vtmp.bv_len
-                       + ( sizeof( "(~=)" ) - 1 );
+               fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(~=)" );
                fstr->bv_val = malloc( fstr->bv_len + 1 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
@@ -333,20 +507,20 @@ rwm_int_filter_map_rewrite(
 
        case LDAP_FILTER_SUBSTRINGS:
                if ( map_attr_value( dc, f->f_sub_desc, &atmp,
-                                       NULL, NULL, remap ) )
+                                       NULL, NULL, RWM_MAP ) )
                {
                        return -1;
                }
 
                /* cannot be a DN ... */
 
-               fstr->bv_len = atmp.bv_len + ( sizeof( "(=*)" ) - 1 );
+               fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
                fstr->bv_val = malloc( fstr->bv_len + 128 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
                        atmp.bv_val );
 
-               if ( f->f_sub_initial.bv_val != NULL ) {
+               if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
                        len = fstr->bv_len;
 
                        filter_escape_value( &f->f_sub_initial, &vtmp );
@@ -362,7 +536,7 @@ rwm_int_filter_map_rewrite(
                }
 
                if ( f->f_sub_any != NULL ) {
-                       for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) {
+                       for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
                                len = fstr->bv_len;
                                filter_escape_value( &f->f_sub_any[i], &vtmp );
 
@@ -376,7 +550,7 @@ rwm_int_filter_map_rewrite(
                        }
                }
 
-               if ( f->f_sub_final.bv_val != NULL ) {
+               if ( !BER_BVISNULL( &f->f_sub_final ) ) {
                        len = fstr->bv_len;
 
                        filter_escape_value( &f->f_sub_final, &vtmp );
@@ -395,12 +569,12 @@ rwm_int_filter_map_rewrite(
 
        case LDAP_FILTER_PRESENT:
                if ( map_attr_value( dc, f->f_desc, &atmp,
-                                       NULL, NULL, remap ) )
+                                       NULL, NULL, RWM_MAP ) )
                {
                        return -1;
                }
 
-               fstr->bv_len = atmp.bv_len + ( sizeof( "(=*)" ) - 1 );
+               fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
                fstr->bv_val = malloc( fstr->bv_len + 1 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
@@ -410,7 +584,7 @@ rwm_int_filter_map_rewrite(
        case LDAP_FILTER_AND:
        case LDAP_FILTER_OR:
        case LDAP_FILTER_NOT:
-               fstr->bv_len = sizeof( "(%)" ) - 1;
+               fstr->bv_len = STRLENOF( "(%)" );
                fstr->bv_val = malloc( fstr->bv_len + 128 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
@@ -420,7 +594,7 @@ rwm_int_filter_map_rewrite(
                for ( p = f->f_list; p != NULL; p = p->f_next ) {
                        len = fstr->bv_len;
 
-                       if ( rwm_int_filter_map_rewrite( dc, p, &vtmp, remap ) )
+                       if ( rwm_int_filter_map_rewrite( dc, p, &vtmp ) )
                        {
                                return -1;
                        }
@@ -439,30 +613,28 @@ rwm_int_filter_map_rewrite(
        case LDAP_FILTER_EXT: {
                if ( f->f_mr_desc ) {
                        if ( map_attr_value( dc, f->f_mr_desc, &atmp,
-                                               &f->f_mr_value, &vtmp, remap ) )
+                                               &f->f_mr_value, &vtmp, RWM_MAP ) )
                        {
                                return -1;
                        }
 
                } else {
-                       atmp.bv_len = 0;
-                       atmp.bv_val = "";
-                       
+                       BER_BVSTR( &atmp, "" );
                        filter_escape_value( &f->f_mr_value, &vtmp );
                }
                        
 
                fstr->bv_len = atmp.bv_len +
-                       ( f->f_mr_dnattrs ? sizeof( ":dn" ) - 1 : 0 ) +
+                       ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
                        ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
-                       vtmp.bv_len + ( sizeof( "(:=)" ) - 1 );
+                       vtmp.bv_len + STRLENOF( "(:=)" );
                fstr->bv_val = malloc( fstr->bv_len + 1 );
 
                snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
                        atmp.bv_val,
                        f->f_mr_dnattrs ? ":dn" : "",
-                       f->f_mr_rule_text.bv_len ? ":" : "",
-                       f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
+                       !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
+                       !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
                        vtmp.bv_val );
                ber_memfree( vtmp.bv_val );
                } break;
@@ -501,14 +673,13 @@ int
 rwm_filter_map_rewrite(
                dncookie                *dc,
                Filter                  *f,
-               struct berval           *fstr,
-               int                     remap )
+               struct berval           *fstr )
 {
        int             rc;
        dncookie        fdc;
        struct berval   ftmp;
 
-       rc = rwm_int_filter_map_rewrite( dc, f, fstr, remap );
+       rc = rwm_int_filter_map_rewrite( dc, f, fstr );
 
 #ifdef ENABLE_REWRITE
        if ( rc != LDAP_SUCCESS ) {
@@ -521,12 +692,13 @@ rwm_filter_map_rewrite(
        fdc.ctx = "searchFilter";
 
        switch ( rewrite_session( fdc.rwmap->rwm_rw, fdc.ctx, 
-                               ( ftmp.bv_len ? ftmp.bv_val : "" ), 
+                               ( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : "" ), 
                                fdc.conn, &fstr->bv_val )) {
        case REWRITE_REGEXEC_OK:
-               if ( fstr->bv_val != NULL ) {
+               if ( !BER_BVISNULL( fstr ) ) {
                        fstr->bv_len = strlen( fstr->bv_val );
                        free( ftmp.bv_val );
+
                } else {
                        *fstr = ftmp;
                }
@@ -576,17 +748,19 @@ rwm_dnattr_rewrite(
        Operation               *op,
        SlapReply               *rs,
        void                    *cookie,
-       BerVarray               a_vals
-       )
+       BerVarray               a_vals,
+       BerVarray               *pa_nvals )
 {
        slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
        struct ldaprwmap        *rwmap = 
                        (struct ldaprwmap *)on->on_bi.bi_private;
 
-       struct berval           bv;
        int                     i, last;
 
        dncookie                dc;
+       struct berval           dn, ndn, *pndn = NULL;
+
+       assert( a_vals );
 
        /*
         * Rewrite the bind dn if needed
@@ -601,11 +775,22 @@ rwm_dnattr_rewrite(
        dc.normalized = 0;
 #endif
 
-       for ( last = 0; a_vals[last].bv_val != NULL; last++ );
+       for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
+       if ( pa_nvals != NULL ) {
+               pndn = &ndn;
+
+               if ( *pa_nvals == NULL ) {
+                       *pa_nvals = ch_malloc( last * sizeof(struct berval) );
+                       memset( *pa_nvals, 0, last * sizeof(struct berval) );
+               }
+       }
        last--;
 
-       for ( i = 0; a_vals[i].bv_val != NULL; i++ ) {
-               switch ( rwm_dn_massage( &dc, &a_vals[i], &bv ) ) {
+       for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
+               int             rc;
+
+               rc = rwm_dn_massage( &dc, &a_vals[i], &dn, pndn );
+               switch ( rc ) {
                case LDAP_UNWILLING_TO_PERFORM:
                        /*
                         * FIXME: need to check if it may be considered 
@@ -615,17 +800,34 @@ rwm_dnattr_rewrite(
                        ch_free( a_vals[i].bv_val );
                        if (last > i ) {
                                a_vals[i] = a_vals[last];
+                               if ( pa_nvals ) {
+                                       (*pa_nvals)[i] = (*pa_nvals)[last];
+                               }
+                       }
+                       BER_BVZERO( &a_vals[last] );
+                       if ( pa_nvals ) {
+                               BER_BVZERO( &(*pa_nvals)[last] );
                        }
-                       a_vals[last].bv_len = 0;
-                       a_vals[last].bv_val = NULL;
                        last--;
                        break;
+               
+               case LDAP_SUCCESS:
+                       if ( !BER_BVISNULL( &dn ) && dn.bv_val != a_vals[i].bv_val ) {
+                               ch_free( a_vals[i].bv_val );
+                               a_vals[i] = dn;
+                               if ( pa_nvals ) {
+                                       if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
+                                               ch_free( (*pa_nvals)[i].bv_val );
+                                       }
+                                       (*pa_nvals)[i] = *pndn;
+                               }
+                       }
+                       break;
 
                default:
                        /* leave attr untouched if massage failed */
-                       if ( bv.bv_val && bv.bv_val != a_vals[i].bv_val ) {
-                               ch_free( a_vals[i].bv_val );
-                               a_vals[i] = bv;
+                       if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
+                               dnNormalize( 0, NULL, NULL, &a_vals[i], &(*pa_nvals)[i], NULL );
                        }
                        break;
                }
@@ -640,14 +842,17 @@ rwm_dnattr_result_rewrite(
        BerVarray               a_vals
 )
 {
-       struct berval   bv;
        int             i, last;
 
-       for ( last = 0; a_vals[last].bv_val; last++ );
+       for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
        last--;
 
-       for ( i = 0; a_vals[i].bv_val; i++ ) {
-               switch ( rwm_dn_massage( dc, &a_vals[i], &bv ) ) {
+       for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
+               struct berval   dn;
+               int             rc;
+               
+               rc = rwm_dn_massage( dc, &a_vals[i], &dn, NULL );
+               switch ( rc ) {
                case LDAP_UNWILLING_TO_PERFORM:
                        /*
                         * FIXME: need to check if it may be considered 
@@ -658,16 +863,15 @@ rwm_dnattr_result_rewrite(
                        if ( last > i ) {
                                a_vals[i] = a_vals[last];
                        }
-                       a_vals[last].bv_val = NULL;
-                       a_vals[last].bv_len = 0;
+                       BER_BVZERO( &a_vals[last] );
                        last--;
                        break;
 
                default:
                        /* leave attr untouched if massage failed */
-                       if ( bv.bv_val && a_vals[i].bv_val != bv.bv_val ) {
+                       if ( !BER_BVISNULL( &dn ) && a_vals[i].bv_val != dn.bv_val ) {
                                LBER_FREE( a_vals[i].bv_val );
-                               a_vals[i] = bv;
+                               a_vals[i] = dn;
                        }
                        break;
                }
@@ -681,7 +885,7 @@ rwm_mapping_free( void *v_mapping )
 {
        struct ldapmapping *mapping = v_mapping;
 
-       if ( mapping[0].m_src.bv_val ) {
+       if ( !BER_BVISNULL( &mapping[0].m_src ) ) {
                ch_free( mapping[0].m_src.bv_val );
        }
 
@@ -698,7 +902,7 @@ rwm_mapping_free( void *v_mapping )
                }
        }
 
-       if ( mapping[0].m_dst.bv_val ) {
+       if ( !BER_BVISNULL( &mapping[0].m_dst ) ) {
                ch_free( mapping[0].m_dst.bv_val );
        }