]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/rwm.c
more about ITS#5940
[openldap] / servers / slapd / overlays / rwm.c
index 1afb4654f31bc914093c747a0f91ec2d7d4b1fea..8f81e040b5d647692275f228056652383dc8b0c0 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2007 The OpenLDAP Foundation.
+ * Copyright 2003-2009 The OpenLDAP Foundation.
  * Portions Copyright 2003 Pierangelo Masarati.
  * All rights reserved.
  *
@@ -38,74 +38,114 @@ typedef struct rwm_op_state {
        OpRequest o_request;
 } rwm_op_state;
 
-static int
-rwm_db_destroy( BackendDB *be, ConfigReply *cr );
-
 typedef struct rwm_op_cb {
        slap_callback cb;
        rwm_op_state ros;
 } rwm_op_cb;
 
 static int
-rwm_op_cleanup( Operation *op, SlapReply *rs )
-{
-       slap_callback   *cb = op->o_callback;
-       rwm_op_state *ros = cb->sc_private;
+rwm_db_destroy( BackendDB *be, ConfigReply *cr );
 
-       if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
-               op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
+static int
+rwm_send_entry( Operation *op, SlapReply *rs );
 
+static void
+rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
+{
+       if ( !BER_BVISNULL( &ros->ro_dn ) ) {
                op->o_req_dn = ros->ro_dn;
+       }
+       if ( !BER_BVISNULL( &ros->ro_ndn ) ) {
                op->o_req_ndn = ros->ro_ndn;
+       }
 
-               if ( !BER_BVISNULL( &ros->r_dn )
-                       && ros->r_dn.bv_val != ros->r_ndn.bv_val )
-               {
-                       ch_free( ros->r_dn.bv_val );
-                       BER_BVZERO( &ros->r_dn );
-               }
+       if ( !BER_BVISNULL( &ros->r_dn )
+               && ros->r_dn.bv_val != ros->ro_dn.bv_val )
+       {
+               assert( ros->r_dn.bv_val != ros->r_ndn.bv_val );
+               ch_free( ros->r_dn.bv_val );
+               BER_BVZERO( &ros->r_dn );
+       }
 
-               if ( !BER_BVISNULL( &ros->r_ndn ) ) {
-                       ch_free( ros->r_ndn.bv_val );
-                       BER_BVZERO( &ros->r_ndn );
-               }
+       if ( !BER_BVISNULL( &ros->r_ndn )
+               && ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
+       {
+               ch_free( ros->r_ndn.bv_val );
+               BER_BVZERO( &ros->r_ndn );
+       }
 
-               switch( ros->r_tag ) {
-               case LDAP_REQ_COMPARE:
-                       if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
-                               op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
-                       op->orc_ava = ros->orc_ava;
-                       break;
-               case LDAP_REQ_MODIFY:
-                       slap_mods_free( op->orm_modlist, 1 );
-                       op->orm_modlist = ros->orm_modlist;
-                       break;
-               case LDAP_REQ_MODRDN:
-                       if ( op->orr_newSup != ros->orr_newSup ) {
-                               ch_free( op->orr_newSup->bv_val );
-                               ch_free( op->orr_nnewSup->bv_val );
-                               op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
-                               op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
-                               op->orr_newSup = ros->orr_newSup;
-                               op->orr_nnewSup = ros->orr_nnewSup;
-                       }
-                       break;
-               case LDAP_REQ_SEARCH:
-                       ch_free( ros->mapped_attrs );
-                       filter_free_x( op, op->ors_filter );
-                       ch_free( op->ors_filterstr.bv_val );
-                       op->ors_attrs = ros->ors_attrs;
-                       op->ors_filter = ros->ors_filter;
-                       op->ors_filterstr = ros->ors_filterstr;
-                       break;
-               case LDAP_REQ_EXTENDED:
-                       if ( op->ore_reqdata != ros->ore_reqdata ) {
-                               ber_bvfree( op->ore_reqdata );
-                               op->ore_reqdata = ros->ore_reqdata;
-                       }
-                       break;
-               default:        break;
+       BER_BVZERO( &ros->ro_dn );
+       BER_BVZERO( &ros->ro_ndn );
+
+       switch( ros->r_tag ) {
+       case LDAP_REQ_COMPARE:
+               if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
+                       op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
+               op->orc_ava = ros->orc_ava;
+               break;
+       case LDAP_REQ_MODIFY:
+               slap_mods_free( op->orm_modlist, 1 );
+               op->orm_modlist = ros->orm_modlist;
+               break;
+       case LDAP_REQ_MODRDN:
+               if ( op->orr_newSup != ros->orr_newSup ) {
+                       ch_free( op->orr_newSup->bv_val );
+                       ch_free( op->orr_nnewSup->bv_val );
+                       op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
+                       op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
+                       op->orr_newSup = ros->orr_newSup;
+                       op->orr_nnewSup = ros->orr_nnewSup;
+               }
+               if ( op->orr_newrdn.bv_val != ros->orr_newrdn.bv_val ) {
+                       ch_free( op->orr_newrdn.bv_val );
+                       ch_free( op->orr_nnewrdn.bv_val );
+                       op->orr_newrdn = ros->orr_newrdn;
+                       op->orr_nnewrdn = ros->orr_nnewrdn;
+               }
+               break;
+       case LDAP_REQ_SEARCH:
+               ch_free( ros->mapped_attrs );
+               filter_free_x( op, op->ors_filter, 1 );
+               ch_free( op->ors_filterstr.bv_val );
+               op->ors_attrs = ros->ors_attrs;
+               op->ors_filter = ros->ors_filter;
+               op->ors_filterstr = ros->ors_filterstr;
+               break;
+       case LDAP_REQ_EXTENDED:
+               if ( op->ore_reqdata != ros->ore_reqdata ) {
+                       ber_bvfree( op->ore_reqdata );
+                       op->ore_reqdata = ros->ore_reqdata;
                }
+               break;
+       case LDAP_REQ_BIND:
+               if ( rs->sr_err == LDAP_SUCCESS ) {
+#if 0
+                       ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
+                       /* too late, c_mutex released */
+                       fprintf( stderr, "*** DN: \"%s\" => \"%s\"\n",
+                               op->o_conn->c_ndn.bv_val,
+                               op->o_req_ndn.bv_val );
+                       ber_bvreplace( &op->o_conn->c_ndn,
+                               &op->o_req_ndn );
+                       ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
+#endif
+               }
+               break;
+       default:        break;
+       }
+}
+
+static int
+rwm_op_cleanup( Operation *op, SlapReply *rs )
+{
+       slap_callback   *cb = op->o_callback;
+       rwm_op_state *ros = cb->sc_private;
+
+       if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
+               op->o_abandon || rs->sr_err == SLAPD_ABANDON )
+       {
+               rwm_op_rollback( op, rs, ros );
+
                op->o_callback = op->o_callback->sc_next;
                op->o_tmpfree( cb, op->o_tmpmemctx );
        }
@@ -179,11 +219,13 @@ rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
 
        if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
                op->o_req_dn = dn;
+               assert( BER_BVISNULL( &ros->r_dn ) );
                ros->r_dn = dn;
        } else {
                op->o_req_dn = ndn;
        }
        op->o_req_ndn = ndn;
+       assert( BER_BVISNULL( &ros->r_ndn ) );
        ros->r_ndn = ndn;
 
        return LDAP_SUCCESS;
@@ -354,7 +396,7 @@ rwm_op_bind( Operation *op, SlapReply *rs )
                return -1;
        }
 
-       op->o_callback = &roc->cb;
+       overlay_callback_after_backover( op, &roc->cb, 1 );
 
        return SLAP_CB_CONTINUE;
 }
@@ -648,11 +690,11 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
                        (struct ldaprwmap *)on->on_bi.bi_private;
        
        int                     rc;
+       dncookie                dc;
 
        rwm_op_cb               *roc = rwm_callback_get( op, rs );
 
        if ( op->orr_newSup ) {
-               dncookie        dc;
                struct berval   nnewSup = BER_BVNULL;
                struct berval   newSup = BER_BVNULL;
 
@@ -682,6 +724,32 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
                }
        }
 
+       /*
+        * Rewrite the newRDN, if needed
+        */
+       {
+               struct berval   newrdn = BER_BVNULL;
+               struct berval   nnewrdn = BER_BVNULL;
+
+               dc.rwmap = rwmap;
+               dc.conn = op->o_conn;
+               dc.rs = rs;
+               dc.ctx = "newRDN";
+               newrdn = op->orr_newrdn;
+               nnewrdn = op->orr_nnewrdn;
+               rc = rwm_dn_massage_pretty_normalize( &dc, &op->orr_newrdn, &newrdn, &nnewrdn );
+               if ( rc != LDAP_SUCCESS ) {
+                       op->o_bd->bd_info = (BackendInfo *)on->on_info;
+                       send_ldap_error( op, rs, rc, "newRDN massage error" );
+                       goto err;
+               }
+
+               if ( op->orr_newrdn.bv_val != newrdn.bv_val ) {
+                       op->orr_newrdn = newrdn;
+                       op->orr_nnewrdn = nnewrdn;
+               }
+       }
+
        /*
         * Rewrite the dn, if needed
         */
@@ -689,6 +757,15 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
        if ( rc != LDAP_SUCCESS ) {
                op->o_bd->bd_info = (BackendInfo *)on->on_info;
                send_ldap_error( op, rs, rc, "renameDN massage error" );
+               goto err;
+       }
+
+       op->o_callback = &roc->cb;
+
+       rc = SLAP_CB_CONTINUE;
+
+       if ( 0 ) {
+err:;
                if ( op->orr_newSup != roc->ros.orr_newSup ) {
                        ch_free( op->orr_newSup->bv_val );
                        ch_free( op->orr_nnewSup->bv_val );
@@ -697,15 +774,16 @@ rwm_op_modrdn( Operation *op, SlapReply *rs )
                        op->orr_newSup = roc->ros.orr_newSup;
                        op->orr_nnewSup = roc->ros.orr_nnewSup;
                }
-               return -1;
-       }
-
-       /* TODO: rewrite newRDN, attribute types, 
-        * values of DN-valued attributes ... */
 
-       op->o_callback = &roc->cb;
+               if ( op->orr_newrdn.bv_val != roc->ros.orr_newrdn.bv_val ) {
+                       ch_free( op->orr_newrdn.bv_val );
+                       ch_free( op->orr_nnewrdn.bv_val );
+                       op->orr_newrdn = roc->ros.orr_newrdn;
+                       op->orr_nnewrdn = roc->ros.orr_nnewrdn;
+               }
+       }
 
-       return SLAP_CB_CONTINUE;
+       return rc;
 }
 
 
@@ -725,6 +803,97 @@ rwm_swap_attrs( Operation *op, SlapReply *rs )
        return SLAP_CB_CONTINUE;
 }
 
+/*
+ * NOTE: this implementation of get/release entry is probably far from
+ * optimal.  The rationale consists in intercepting the request directed
+ * to the underlying database, in order to rewrite/remap the request,
+ * perform it using the modified data, duplicate the resulting entry
+ * and finally free it when release is called.
+ * This implies that subsequent overlays are not called, as the request
+ * is directly shunted to the underlying database.
+ */
+static int
+rwm_entry_release_rw( Operation *op, Entry *e, int rw )
+{
+       slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
+
+       /* can't be ours */
+       if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       /* just free entry if (probably) ours */
+       if ( e->e_private == NULL ) {
+               entry_free( e );
+               return LDAP_SUCCESS;
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+rwm_entry_get_rw( Operation *op, struct berval *ndn,
+       ObjectClass *oc, AttributeDescription *at, int rw, Entry **ep )
+{
+       slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
+       struct ldaprwmap        *rwmap = 
+                       (struct ldaprwmap *)on->on_bi.bi_private;
+
+       int                     rc;
+       dncookie                dc;
+
+       BackendDB               db;
+       Operation               op2;
+       SlapReply               rs = { REP_SEARCH };
+
+       rwm_op_state            ros = { 0 };
+
+       if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       /* massage DN */
+       op2.o_tag = LDAP_REQ_SEARCH;
+       op2 = *op;
+       op2.o_req_dn = *ndn;
+       op2.o_req_ndn = *ndn;
+       rc = rwm_op_dn_massage( &op2, &rs, "searchDN", &ros );
+       if ( rc != LDAP_SUCCESS ) {
+               return LDAP_OTHER;
+       }
+
+       /* map attribute & objectClass */
+       if ( at != NULL ) {
+       }
+
+       if ( oc != NULL ) {
+       }
+
+       /* fetch entry */
+       db = *op->o_bd;
+       op2.o_bd = &db;
+       op2.o_bd->bd_info = (BackendInfo *)on->on_info->oi_orig;
+       op2.ors_attrs = slap_anlist_all_attributes;
+       rc = op2.o_bd->bd_info->bi_entry_get_rw( &op2, &ros.r_ndn, oc, at, rw, ep );
+       if ( rc == LDAP_SUCCESS && *ep != NULL ) {
+               rs.sr_entry = *ep;
+
+               /* duplicate & release */
+               op2.o_bd->bd_info = (BackendInfo *)on;
+               rc = rwm_send_entry( &op2, &rs );
+               if ( rc == SLAP_CB_CONTINUE ) {
+                       *ep = rs.sr_entry;
+                       rc = LDAP_SUCCESS;
+               }
+       }
+
+       if ( ros.r_ndn.bv_val != ndn->bv_val ) {
+               op->o_tmpfree( ros.r_ndn.bv_val, op->o_tmpmemctx );
+       }
+
+       return rc;
+}
+
 static int
 rwm_op_search( Operation *op, SlapReply *rs )
 {
@@ -800,14 +969,16 @@ error_return:;
        }
 
        if ( f != NULL ) {
-               filter_free_x( op, f );
+               filter_free_x( op, f, 1 );
        }
 
        if ( !BER_BVISNULL( &fstr ) ) {
                ch_free( fstr.bv_val );
        }
 
+       rwm_op_rollback( op, rs, &roc->ros );
        op->oq_search = roc->ros.oq_search;
+       op->o_tmpfree( roc, op->o_tmpmemctx );
 
        op->o_bd->bd_info = (BackendInfo *)on->on_info;
        send_ldap_error( op, rs, rc, text );
@@ -844,8 +1015,11 @@ rwm_exop_passwd( Operation *op, SlapReply *rs )
        }
 
        if ( !BER_BVISNULL( &id ) ) {
+               char idNul = id.bv_val[id.bv_len];
+               id.bv_val[id.bv_len] = '\0';
                rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
                                &op->o_req_ndn, op->o_tmpmemctx );
+               id.bv_val[id.bv_len] = idNul;
                if ( rs->sr_err != LDAP_SUCCESS ) {
                        rs->sr_text = "Invalid DN";
                        return rs->sr_err;
@@ -1046,37 +1220,44 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
 
                                /* try to normalize mapped Attributes if the original 
                                 * AttributeType was not normalized */
-                               if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS) && 
-                                       (!(*ap)->a_desc->ad_type->sat_equality || 
+                               if ( (!(*ap)->a_desc->ad_type->sat_equality || 
                                        !(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
                                        mapping->m_dst_ad->ad_type->sat_equality &&
                                        mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
                                {
-                                       int i = 0;
-
-                                       last = (*ap)->a_numvals;
-                                       if ( last )
+                                       if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS))
                                        {
-                                               (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
-
-                                               for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
-                                                       int             rc;
-                                                       /*
-                                                        * check that each value is valid per syntax
-                                                        * and pretty if appropriate
-                                                        */
-                                                       rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
-                                                               SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
-                                                               mapping->m_dst_ad->ad_type->sat_syntax,
-                                                               mapping->m_dst_ad->ad_type->sat_equality,
-                                                               &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
-                                                               NULL );
-
-                                                       if ( rc != LDAP_SUCCESS ) {
-                                                               BER_BVZERO( &(*ap)->a_nvals[i] );
+                                               int i = 0;
+
+                                               last = (*ap)->a_numvals;
+                                               if ( last )
+                                               {
+                                                       (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
+
+                                                       for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
+                                                               int             rc;
+                                                               /*
+                                                                * check that each value is valid per syntax
+                                                                * and pretty if appropriate
+                                                                */
+                                                               rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
+                                                                       SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+                                                                       mapping->m_dst_ad->ad_type->sat_syntax,
+                                                                       mapping->m_dst_ad->ad_type->sat_equality,
+                                                                       &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
+                                                                       NULL );
+
+                                                               if ( rc != LDAP_SUCCESS ) {
+                                                                       BER_BVZERO( &(*ap)->a_nvals[i] );
+                                                               }
                                                        }
+                                                       BER_BVZERO( &(*ap)->a_nvals[i] );
                                                }
-                                               BER_BVZERO( &(*ap)->a_nvals[i] );
+
+                                       } else {
+                                               assert( (*ap)->a_nvals == (*ap)->a_vals );
+                                               (*ap)->a_nvals = NULL;
+                                               ber_bvarray_dup_x( &(*ap)->a_nvals, (*ap)->a_vals, NULL );
                                        }
                                }
 
@@ -1132,7 +1313,9 @@ remove_oc:;
                                        last--;
                                        bv--;
 
-                               } else if ( mapped.bv_val != bv[0].bv_val ) {
+                               } else if ( mapped.bv_val != bv[0].bv_val
+                                       && ber_bvstrcasecmp( &mapped, &bv[0] ) != 0 )
+                               {
                                        int     i;
 
                                        for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
@@ -1178,7 +1361,7 @@ remove_oc:;
                                || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
                {
                        dc.ctx = "searchAttrDN";
-                       rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
+                       rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals, (*ap)->a_nvals );
                        if ( rc != LDAP_SUCCESS ) {
                                goto cleanup_attr;
                        }
@@ -1224,7 +1407,9 @@ cleanup_attr:;
                                        mod.sm_type = mod.sm_desc->ad_cname;
                                        mod.sm_numvals = (*tap)->a_numvals;
                                        mod.sm_values = (*tap)->a_vals;
-                                       mod.sm_nvalues = (*tap)->a_nvals;
+                                       if ( (*tap)->a_nvals != (*tap)->a_vals ) {
+                                               mod.sm_nvalues = (*tap)->a_nvals;
+                                       }
 
                                        (void)modify_add_values( &e, &mod,
                                                /* permissive */ 1,
@@ -1320,7 +1505,7 @@ rwm_send_entry( Operation *op, SlapReply *rs )
        (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
 
        if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
-               be_entry_release_rw( op, rs->sr_entry, 0 );
+               overlay_entry_release_ov( op, rs->sr_entry, 0, on );
        }
 
        rs->sr_entry = e;
@@ -1611,6 +1796,7 @@ rwm_db_config(
                                fname, lineno, argv[ 1 ] );
                        return 1;
                }
+
        } else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) ==  0 ) {
                if ( argc !=2 ) { 
                        fprintf( stderr,
@@ -1644,7 +1830,6 @@ rwm_db_config(
 enum {
        /* rewrite */
        RWM_CF_REWRITE = 1,
-       RWM_CF_SUFFIXMASSAGE,
 
        /* map */
        RWM_CF_MAP,
@@ -1655,8 +1840,10 @@ enum {
 };
 
 static slap_verbmasks t_f_mode[] = {
+       { BER_BVC( "true" ),            RWM_F_SUPPORT_T_F },
        { BER_BVC( "yes" ),             RWM_F_SUPPORT_T_F },
        { BER_BVC( "discover" ),        RWM_F_SUPPORT_T_F_DISCOVER },
+       { BER_BVC( "false" ),           RWM_F_NONE },
        { BER_BVC( "no" ),              RWM_F_NONE },
        { BER_BVNULL,                   0 }
 };
@@ -1666,7 +1853,7 @@ static ConfigDriver rwm_cf_gen;
 static ConfigTable rwmcfg[] = {
        { "rwm-rewrite", "rewrite",
                2, 0, STRLENOF("rwm-rewrite"),
-               ARG_MAGIC|ARG_QUOTE|RWM_CF_REWRITE, rwm_cf_gen,
+               ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
                "( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
                        "DESC 'Rewrites strings' "
                        "EQUALITY caseIgnoreMatch "
@@ -1675,7 +1862,7 @@ static ConfigTable rwmcfg[] = {
                NULL, NULL },
 
        { "rwm-suffixmassage", "[virtual]> <real",
-               2, 3, 0, ARG_MAGIC|RWM_CF_SUFFIXMASSAGE, rwm_cf_gen,
+               2, 3, 0, ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
                NULL, NULL, NULL },
                
        { "rwm-t-f-support", "true|false|discover",
@@ -1760,6 +1947,53 @@ slap_rewrite_unparse( BerVarray in, BerVarray *out )
        *out = bva;
 }
 
+static int
+rwm_bva_rewrite_add(
+       struct ldaprwmap        *rwmap,
+       const char              *argv[] )
+{
+       char            *line;
+       struct berval   bv;
+
+       line = ldap_charray2str( argv, "\" \"" );
+       if ( line != NULL ) {
+               int     len = strlen( argv[ 0 ] );
+
+               ber_str2bv( line, 0, 0, &bv );
+               AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
+                       bv.bv_len - ( len + 1 ) );
+               bv.bv_val[ bv.bv_len - 1 ] = '"';
+               ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
+       }
+
+       return 0;
+}
+
+static int
+rwm_info_init( struct ldaprwmap *rwmap )
+{
+       char                    *rargv[ 3 ];
+
+       rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
+       if ( rwmap->rwm_rw == NULL ) {
+               return -1;
+       }
+
+       /* this rewriteContext by default must be null;
+        * rules can be added if required */
+       rargv[ 0 ] = "rewriteContext";
+       rargv[ 1 ] = "searchFilter";
+       rargv[ 2 ] = NULL;
+       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
+
+       rargv[ 0 ] = "rewriteContext";
+       rargv[ 1 ] = "default";
+       rargv[ 2 ] = NULL;
+       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
+
+       return 0;
+}
+
 static int
 rwm_cf_gen( ConfigArgs *c )
 {
@@ -1769,6 +2003,7 @@ rwm_cf_gen( ConfigArgs *c )
 
        BackendDB               db;
        char                    *argv0;
+       int                     idx0 = 0;
        int                     rc = 0;
 
        db = *c->be;
@@ -1826,7 +2061,6 @@ rwm_cf_gen( ConfigArgs *c )
                switch ( c->type ) {
                case RWM_CF_REWRITE:
                        if ( c->valx >= 0 ) {
-                               /* single modification is not allowed */
                                rc = 1;
 
                        } else if ( rwmap->rwm_rw != NULL ) {
@@ -1835,6 +2069,8 @@ rwm_cf_gen( ConfigArgs *c )
 
                                ber_bvarray_free( rwmap->rwm_bva_rewrite );
                                rwmap->rwm_bva_rewrite = NULL;
+
+                               rc = rwm_info_init( rwmap );
                        }
                        break;
 
@@ -1873,59 +2109,35 @@ rwm_cf_gen( ConfigArgs *c )
                return rc;
        }
 
+       if ( strncasecmp( c->argv[ 0 ], "olcRwm", STRLENOF( "olcRwm" ) ) == 0 ) {
+               idx0 = 1;
+       }
+
        switch ( c->type ) {
        case RWM_CF_REWRITE:
-               argv0 = c->argv[ 0 ];
-               c->argv[ 0 ] += STRLENOF( "rwm-" );
-               rc = rwm_rw_config( &db, c->fname, c->lineno, c->argc, c->argv );
-               c->argv[ 0 ] = argv0;
-               if ( rc ) {
+               if ( c->valx >= 0 ) {
                        return 1;
+               }
 
-               } else {
-                       char            *line;
-                       struct berval   bv;
-
-                       line = ldap_charray2str( c->argv, "\" \"" );
-                       if ( line != NULL ) {
-                               int     len = strlen( c->argv[ 0 ] );
-
-                               ber_str2bv( line, 0, 0, &bv );
-                               AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
-                                       bv.bv_len - ( len + 1 ) );
-                               bv.bv_val[ bv.bv_len - 1 ] = '"';
-                               ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
-                       }
+               argv0 = c->argv[ idx0 ];
+               if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
+                       return 1;
                }
-               break;
+               c->argv[ idx0 ] += STRLENOF( "rwm-" );
+               if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
+                       rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
+                               c->argc - idx0, &c->argv[ idx0 ] );
 
-       case RWM_CF_SUFFIXMASSAGE:
-               argv0 = c->argv[ 0 ];
-               c->argv[ 0 ] += STRLENOF( "rwm-" );
-               rc = rwm_suffixmassage_config( &db, c->fname, c->lineno, c->argc, c->argv );
-               c->argv[ 0 ] = argv0;
+               } else {
+                       rc = rwm_rw_config( &db, c->fname, c->lineno,
+                               c->argc - idx0, &c->argv[ idx0 ] );
+               }
+               c->argv[ idx0 ] = argv0;
                if ( rc ) {
                        return 1;
 
                } else {
-                       char            *line;
-                       struct berval   bv;
-
-                       /* FIXME: not optimal; in fact, this keeps track
-                        * of the fact that a set of rules was added
-                        * using the rwm-suffixmassage shortcut, but the
-                        * rules are not clarified */
-
-                       line = ldap_charray2str( c->argv, "\" \"" );
-                       if ( line != NULL ) {
-                               int     len = strlen( c->argv[ 0 ] );
-
-                               ber_str2bv( line, 0, 0, &bv );
-                               AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
-                                       bv.bv_len - ( len + 1 ) );
-                               bv.bv_val[ bv.bv_len - 1 ] = '"';
-                               ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
-                       }
+                       rwm_bva_rewrite_add( rwmap, &c->argv[ idx0 ] );
                }
                break;
 
@@ -1941,6 +2153,10 @@ rwm_cf_gen( ConfigArgs *c )
                break;
 
        case RWM_CF_MAP:
+               if ( c->valx >= 0 ) {
+                       return 1;
+               }
+
                argv0 = c->argv[ 0 ];
                c->argv[ 0 ] += STRLENOF( "rwm-" );
                rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
@@ -1983,28 +2199,11 @@ rwm_db_init(
 {
        slap_overinst           *on = (slap_overinst *) be->bd_info;
        struct ldaprwmap        *rwmap;
-       char                    *rargv[ 3 ];
        int                     rc = 0;
 
        rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
 
-       rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
-       if ( rwmap->rwm_rw == NULL ) {
-               rc = -1;
-               goto error_return;
-       }
-
-       /* this rewriteContext by default must be null;
-        * rules can be added if required */
-       rargv[ 0 ] = "rewriteContext";
-       rargv[ 1 ] = "searchFilter";
-       rargv[ 2 ] = NULL;
-       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
-
-       rargv[ 0 ] = "rewriteContext";
-       rargv[ 1 ] = "default";
-       rargv[ 2 ] = NULL;
-       rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
+       rc = rwm_info_init( rwmap );
 
 error_return:;
        on->on_bi.bi_private = (void *)rwmap;
@@ -2078,6 +2277,10 @@ rwm_initialize( void )
        rwm.on_bi.bi_op_delete = rwm_op_delete;
        rwm.on_bi.bi_op_unbind = rwm_op_unbind;
        rwm.on_bi.bi_extended = rwm_extended;
+#if 1 /* TODO */
+       rwm.on_bi.bi_entry_release_rw = rwm_entry_release_rw;
+       rwm.on_bi.bi_entry_get_rw = rwm_entry_get_rw;
+#endif
 
        rwm.on_bi.bi_operational = rwm_operational;
        rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;