]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/memberof.c
Revert "update entryCSN (and operational attrs in general) when changing memberOf...
[openldap] / servers / slapd / overlays / memberof.c
index 9bc2497cd61dfb645c88a6e2cca8f1a8536e062d..7697a085230aa63ea4d4178b3555f91d47ae65e3 100644 (file)
@@ -155,6 +155,8 @@ typedef struct memberof_t {
 #define        MEMBEROF_FREFINT        0x04U
 #define        MEMBEROF_FREVERSE       0x08U
 
+       ber_int_t               mo_dangling_err;
+
 #define MEMBEROF_CHK(mo,f) \
        (((mo)->mo_flags & (f)) == (f))
 #define MEMBEROF_DANGLING_CHECK(mo) \
@@ -176,71 +178,19 @@ typedef enum memberof_is_t {
        MEMBEROF_IS_BOTH = (MEMBEROF_IS_GROUP|MEMBEROF_IS_MEMBER)
 } memberof_is_t;
 
-/*
- * failover storage for member attribute values of groups being deleted
- * handles [no]thread cases.
- */
-static BerVarray       saved_member_vals;
-static BerVarray       saved_memberof_vals;
-
-static void
-memberof_saved_member_free( void *key, void *data )
-{
-       ber_bvarray_free( (BerVarray)data );
-}
-
-static BerVarray
-memberof_saved_member_get( Operation *op, void *keyp )
-{
-       BerVarray       vals;
-       BerVarray       *key = (BerVarray *)keyp;
-
-       assert( op != NULL );
-
-       if ( op->o_threadctx == NULL ) {
-               vals = *key;
-               *key = NULL;
-
-       } else {
-               ldap_pvt_thread_pool_getkey( op->o_threadctx,
-                               key, (void **)&vals, NULL );
-               ldap_pvt_thread_pool_setkey( op->o_threadctx,
-                               key, NULL, NULL );
-       }
-
-       return vals;
-}
-
-static void
-memberof_saved_member_set( Operation *op, void *keyp, BerVarray vals )
-{
-       BerVarray       saved_vals = NULL;
-       BerVarray       *key = (BerVarray*)keyp;
-
-       assert( op != NULL );
-
-       if ( vals ) {
-               ber_bvarray_dup_x( &saved_vals, vals, NULL );
-       }
-
-       if ( op->o_threadctx == NULL ) {
-               if ( *key ) {
-                       ber_bvarray_free( *key );
-               }
-               *key = saved_vals;
-
-       } else {
-               ldap_pvt_thread_pool_setkey( op->o_threadctx, key,
-                               saved_vals, memberof_saved_member_free );
-       }
-}
-
 typedef struct memberof_cookie_t {
        AttributeDescription    *ad;
-       void                    *key;
+       BerVarray               vals;
        int                     foundit;
 } memberof_cookie_t;
 
+typedef struct memberof_cbinfo_t {
+       slap_overinst *on;
+       BerVarray member;
+       BerVarray memberof;
+       memberof_is_t what;
+} memberof_cbinfo_t;
+       
 static int
 memberof_isGroupOrMember_cb( Operation *op, SlapReply *rs )
 {
@@ -272,19 +222,10 @@ memberof_saveMember_cb( Operation *op, SlapReply *rs )
                assert( rs->sr_entry->e_attrs != NULL );
 
                a = attr_find( rs->sr_entry->e_attrs, mc->ad );
+               if ( a != NULL ) {
+                       ber_bvarray_dup_x( &mc->vals, a->a_nvals, op->o_tmpmemctx );
 
-               assert( a != NULL );
-
-               memberof_saved_member_set( op, mc->key, a->a_nvals );
-
-               if ( attr_find( a->a_next, mc->ad ) != NULL ) {
-                       Debug( LDAP_DEBUG_ANY,
-                               "%s: memberof_saveMember_cb(\"%s\"): "
-                               "more than one occurrence of \"%s\" "
-                               "attribute.\n",
-                               op->o_log_prefix,
-                               rs->sr_entry->e_name.bv_val,
-                               mc->ad->ad_cname.bv_val );
+                       assert( attr_find( a->a_next, mc->ad ) == NULL );
                }
        }
 
@@ -296,21 +237,20 @@ memberof_saveMember_cb( Operation *op, SlapReply *rs )
  * attribute values of groups being deleted.
  */
 static int
-memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp )
+memberof_isGroupOrMember( Operation *op, memberof_cbinfo_t *mci )
 {
-       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
+       slap_overinst           *on = mci->on;
        memberof_t              *mo = (memberof_t *)on->on_bi.bi_private;
 
        Operation               op2 = *op;
-       SlapReply               rs2 = { REP_RESULT };
        slap_callback           cb = { 0 };
-       memberof_cookie_t       mc;
+       BackendInfo     *bi = op->o_bd->bd_info;
        AttributeName           an[ 2 ];
 
        memberof_is_t           iswhat = MEMBEROF_IS_NONE;
+       memberof_cookie_t       mc;
 
-       assert( iswhatp != NULL );
-       assert( *iswhatp != MEMBEROF_IS_NONE );
+       assert( mci->what != MEMBEROF_IS_NONE );
 
        cb.sc_private = &mc;
        if ( op->o_tag == LDAP_REQ_DELETE ) {
@@ -334,10 +274,12 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp )
        op2.ors_slimit = 1;
        op2.ors_tlimit = SLAP_NO_LIMIT;
 
-       if ( *iswhatp & MEMBEROF_IS_GROUP ) {
+       if ( mci->what & MEMBEROF_IS_GROUP ) {
+               SlapReply       rs2 = { REP_RESULT };
+
                mc.ad = mo->mo_ad_member;
-               mc.key = &saved_member_vals;
                mc.foundit = 0;
+               mc.vals = NULL;
                an[ 0 ].an_desc = mo->mo_ad_member;
                an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname;
                op2.ors_filterstr = mo->mo_groupFilterstr;
@@ -345,20 +287,21 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp )
 
                op2.o_bd->bd_info = (BackendInfo *)on->on_info;
                (void)op->o_bd->be_search( &op2, &rs2 );
-               op2.o_bd->bd_info = (BackendInfo *)on;
+               op2.o_bd->bd_info = bi;
 
                if ( mc.foundit ) {
                        iswhat |= MEMBEROF_IS_GROUP;
+                       if ( mc.vals ) mci->member = mc.vals;
 
-               } else {
-                       memberof_saved_member_set( op, mc.key, NULL );
                }
        }
 
-       if ( *iswhatp & MEMBEROF_IS_MEMBER ) {
+       if ( mci->what & MEMBEROF_IS_MEMBER ) {
+               SlapReply       rs2 = { REP_RESULT };
+
                mc.ad = mo->mo_ad_memberof;
-               mc.key = &saved_memberof_vals;
                mc.foundit = 0;
+               mc.vals = NULL;
                an[ 0 ].an_desc = mo->mo_ad_memberof;
                an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname;
                op2.ors_filterstr = mo->mo_memberFilterstr;
@@ -366,17 +309,16 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp )
 
                op2.o_bd->bd_info = (BackendInfo *)on->on_info;
                (void)op->o_bd->be_search( &op2, &rs2 );
-               op2.o_bd->bd_info = (BackendInfo *)on;
+               op2.o_bd->bd_info = bi;
 
                if ( mc.foundit ) {
                        iswhat |= MEMBEROF_IS_MEMBER;
+                       if ( mc.vals ) mci->memberof = mc.vals;
 
-               } else {
-                       memberof_saved_member_set( op, mc.key, NULL );
                }
        }
 
-       *iswhatp = iswhat;
+       mci->what = iswhat;
 
        return LDAP_SUCCESS;
 }
@@ -384,10 +326,9 @@ memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp )
 /*
  * response callback that adds memberof values when a group is modified.
  */
-static int
+static void
 memberof_value_modify(
        Operation               *op,
-       SlapReply               *rs,
        struct berval           *ndn,
        AttributeDescription    *ad,
        struct berval           *old_dn,
@@ -395,7 +336,8 @@ memberof_value_modify(
        struct berval           *new_dn,
        struct berval           *new_ndn )
 {
-       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       memberof_cbinfo_t *mci = op->o_callback->sc_private;
+       slap_overinst   *on = mci->on;
        memberof_t      *mo = (memberof_t *)on->on_bi.bi_private;
 
        Operation       op2 = *op;
@@ -403,34 +345,38 @@ memberof_value_modify(
        slap_callback   cb = { NULL, slap_null_cb, NULL, NULL };
        Modifications   mod[ 2 ] = { { { 0 } } }, *ml;
        struct berval   values[ 4 ], nvalues[ 4 ];
+       int             mcnt = 0;
 
        op2.o_tag = LDAP_REQ_MODIFY;
 
        op2.o_req_dn = *ndn;
        op2.o_req_ndn = *ndn;
 
-       op2.o_bd->bd_info = (BackendInfo *)on->on_info;
-
        op2.o_callback = &cb;
        op2.o_dn = op->o_bd->be_rootdn;
        op2.o_ndn = op->o_bd->be_rootndn;
+       op2.orm_modlist = NULL;
+
+       if ( !BER_BVISNULL( &mo->mo_ndn ) ) {
+               ml = &mod[ mcnt ];
+               ml->sml_numvals = 1;
+               ml->sml_values = &values[ 0 ];
+               ml->sml_values[ 0 ] = mo->mo_dn;
+               BER_BVZERO( &ml->sml_values[ 1 ] );
+               ml->sml_nvalues = &nvalues[ 0 ];
+               ml->sml_nvalues[ 0 ] = mo->mo_ndn;
+               BER_BVZERO( &ml->sml_nvalues[ 1 ] );
+               ml->sml_desc = slap_schema.si_ad_modifiersName;
+               ml->sml_type = ml->sml_desc->ad_cname;
+               ml->sml_op = LDAP_MOD_REPLACE;
+               ml->sml_flags = SLAP_MOD_INTERNAL;
+               ml->sml_next = op2.orm_modlist;
+               op2.orm_modlist = ml;
+
+               mcnt++;
+       }
 
-       ml = &mod[ 0 ];
-       ml->sml_numvals = 1;
-       ml->sml_values = &values[ 0 ];
-       ml->sml_values[ 0 ] = mo->mo_dn;
-       BER_BVZERO( &ml->sml_values[ 1 ] );
-       ml->sml_nvalues = &nvalues[ 0 ];
-       ml->sml_nvalues[ 0 ] = mo->mo_ndn;
-       BER_BVZERO( &ml->sml_nvalues[ 1 ] );
-       ml->sml_desc = slap_schema.si_ad_modifiersName;
-       ml->sml_type = ml->sml_desc->ad_cname;
-       ml->sml_op = LDAP_MOD_REPLACE;
-       ml->sml_flags = SLAP_MOD_INTERNAL;
-       ml->sml_next = NULL;
-       op2.orm_modlist = ml;
-
-       ml = &mod[ 1 ];
+       ml = &mod[ mcnt ];
        ml->sml_numvals = 1;
        ml->sml_values = &values[ 2 ];
        BER_BVZERO( &ml->sml_values[ 1 ] );
@@ -439,58 +385,85 @@ memberof_value_modify(
        ml->sml_desc = ad;
        ml->sml_type = ml->sml_desc->ad_cname;
        ml->sml_flags = SLAP_MOD_INTERNAL;
-       ml->sml_next = NULL;
-       op2.orm_modlist->sml_next = ml;
+       ml->sml_next = op2.orm_modlist;
+       op2.orm_modlist = ml;
 
        if ( new_ndn != NULL ) {
+               BackendInfo *bi = op2.o_bd->bd_info;
+               OpExtra oex;
+
                assert( !BER_BVISNULL( new_dn ) );
                assert( !BER_BVISNULL( new_ndn ) );
 
-               ml = &mod[ 1 ];
+               ml = &mod[ mcnt ];
                ml->sml_op = LDAP_MOD_ADD;
 
                ml->sml_values[ 0 ] = *new_dn;
                ml->sml_nvalues[ 0 ] = *new_ndn;
 
+               oex.oe_key = (void *)&memberof;
+               LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next);
+               op2.o_bd->bd_info = (BackendInfo *)on->on_info;
                (void)op->o_bd->be_modify( &op2, &rs2 );
+               op2.o_bd->bd_info = bi;
+               LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next);
                if ( rs2.sr_err != LDAP_SUCCESS ) {
                        char buf[ SLAP_TEXT_BUFLEN ];
                        snprintf( buf, sizeof( buf ),
-                               "memberof_value_modify %s=\"%s\" failed err=%d",
-                               ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err );
-                       Debug( LDAP_DEBUG_ANY, "%s: %s\n", op->o_log_prefix, buf, 0 );
+                               "memberof_value_modify DN=\"%s\" add %s=\"%s\" failed err=%d",
+                               op2.o_req_dn.bv_val, ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err );
+                       Debug( LDAP_DEBUG_ANY, "%s: %s\n",
+                               op->o_log_prefix, buf, 0 );
                }
 
-               assert( op2.orm_modlist == &mod[ 0 ] );
-               assert( op2.orm_modlist->sml_next == &mod[ 1 ] );
-               ml = op2.orm_modlist->sml_next->sml_next;
+               assert( op2.orm_modlist == &mod[ mcnt ] );
+               assert( mcnt == 0 || op2.orm_modlist->sml_next == &mod[ 0 ] );
+               ml = op2.orm_modlist->sml_next;
+               if ( mcnt == 1 ) {
+                       assert( ml == &mod[ 0 ] );
+                       ml = ml->sml_next;
+               }
                if ( ml != NULL ) {
                        slap_mods_free( ml, 1 );
                }
+
+               mod[ 0 ].sml_next = NULL;
        }
 
        if ( old_ndn != NULL ) {
+               BackendInfo *bi = op2.o_bd->bd_info;
+               OpExtra oex;
+
                assert( !BER_BVISNULL( old_dn ) );
                assert( !BER_BVISNULL( old_ndn ) );
 
-               ml = &mod[ 1 ];
+               ml = &mod[ mcnt ];
                ml->sml_op = LDAP_MOD_DELETE;
 
                ml->sml_values[ 0 ] = *old_dn;
                ml->sml_nvalues[ 0 ] = *old_ndn;
 
+               oex.oe_key = (void *)&memberof;
+               LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next);
+               op2.o_bd->bd_info = (BackendInfo *)on->on_info;
                (void)op->o_bd->be_modify( &op2, &rs2 );
+               op2.o_bd->bd_info = bi;
+               LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next);
                if ( rs2.sr_err != LDAP_SUCCESS ) {
                        char buf[ SLAP_TEXT_BUFLEN ];
                        snprintf( buf, sizeof( buf ),
-                               "memberof_value_modify %s=\"%s\" failed err=%d",
-                               ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err );
-                       Debug( LDAP_DEBUG_ANY, "%s: %s\n", op->o_log_prefix, buf, 0 );
+                               "memberof_value_modify DN=\"%s\" delete %s=\"%s\" failed err=%d",
+                               op2.o_req_dn.bv_val, ad->ad_cname.bv_val, old_dn->bv_val, rs2.sr_err );
+                       Debug( LDAP_DEBUG_ANY, "%s: %s\n",
+                               op->o_log_prefix, buf, 0 );
                }
 
-               assert( op2.orm_modlist == &mod[ 0 ] );
-               assert( op2.orm_modlist->sml_next == &mod[ 1 ] );
-               ml = op2.orm_modlist->sml_next->sml_next;
+               assert( op2.orm_modlist == &mod[ mcnt ] );
+               ml = op2.orm_modlist->sml_next;
+               if ( mcnt == 1 ) {
+                       assert( ml == &mod[ 0 ] );
+                       ml = ml->sml_next;
+               }
                if ( ml != NULL ) {
                        slap_mods_free( ml, 1 );
                }
@@ -500,12 +473,28 @@ memberof_value_modify(
         * add will fail; better split in two operations, although
         * not optimal in terms of performance.  At least it would
         * move towards self-repairing capabilities. */
+}
 
-       op2.o_bd->bd_info = (BackendInfo *)on;
-
-       return rs2.sr_err;
+static int
+memberof_cleanup( Operation *op, SlapReply *rs )
+{
+       slap_callback *sc = op->o_callback;
+       memberof_cbinfo_t *mci = sc->sc_private;
+
+       op->o_callback = sc->sc_next;
+       if ( mci->memberof )
+               ber_bvarray_free_x( mci->memberof, op->o_tmpmemctx );
+       if ( mci->member )
+               ber_bvarray_free_x( mci->member, op->o_tmpmemctx );
+       op->o_tmpfree( sc, op->o_tmpmemctx );
+       return 0;
 }
 
+static int memberof_res_add( Operation *op, SlapReply *rs );
+static int memberof_res_delete( Operation *op, SlapReply *rs );
+static int memberof_res_modify( Operation *op, SlapReply *rs );
+static int memberof_res_modrdn( Operation *op, SlapReply *rs );
+
 static int
 memberof_op_add( Operation *op, SlapReply *rs )
 {
@@ -516,6 +505,14 @@ memberof_op_add( Operation *op, SlapReply *rs )
        int             rc = SLAP_CB_CONTINUE;
        int             i;
        struct berval   save_dn, save_ndn;
+       slap_callback *sc;
+       memberof_cbinfo_t *mci;
+       OpExtra         *oex;
+
+       LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
+               if ( oex->oe_key == (void *)&memberof )
+                       return SLAP_CB_CONTINUE;
+       }
 
        if ( op->ora_e->e_attrs == NULL ) {
                /* FIXME: global overlay; need to deal with */
@@ -545,7 +542,7 @@ memberof_op_add( Operation *op, SlapReply *rs )
                        && is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) )
        {
                op->o_dn = op->o_bd->be_rootdn;
-               op->o_dn = op->o_bd->be_rootndn;
+               op->o_ndn = op->o_bd->be_rootndn;
                op->o_bd->bd_info = (BackendInfo *)on->on_info;
 
                for ( ap = &op->ora_e->e_attrs; *ap; ) {
@@ -561,6 +558,10 @@ memberof_op_add( Operation *op, SlapReply *rs )
                        for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
                                Entry           *e = NULL;
 
+                               /* ITS#6670 Ignore member pointing to this entry */
+                               if ( dn_match( &a->a_nvals[i], &save_ndn ))
+                                       continue;
+
                                rc = be_entry_get_rw( op, &a->a_nvals[ i ],
                                                NULL, NULL, 0, &e );
                                if ( rc == LDAP_SUCCESS ) {
@@ -569,7 +570,7 @@ memberof_op_add( Operation *op, SlapReply *rs )
                                }
 
                                if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-                                       rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+                                       rc = rs->sr_err = mo->mo_dangling_err;
                                        rs->sr_text = "adding non-existing object "
                                                "as group member";
                                        send_ldap_result( op, rs );
@@ -602,6 +603,7 @@ memberof_op_add( Operation *op, SlapReply *rs )
                                                        sizeof( struct berval ) * ( j - i ) );
                                        }
                                        i--;
+                                       a->a_numvals--;
                                }
                        }
 
@@ -638,6 +640,10 @@ memberof_op_add( Operation *op, SlapReply *rs )
                                send_ldap_result( op, rs );
                                goto done;
                        }
+                       /* ITS#6670 Ignore member pointing to this entry */
+                       if ( dn_match( &a->a_nvals[i], &save_ndn ))
+                               continue;
+
                        rc = be_entry_get_rw( op, &a->a_nvals[ i ],
                                        NULL, NULL, 0, &e );
                        op->o_bd->bd_info = (BackendInfo *)on;
@@ -647,7 +653,7 @@ memberof_op_add( Operation *op, SlapReply *rs )
                                }
 
                                if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-                                       rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+                                       rc = rs->sr_err = mo->mo_dangling_err;
                                        rs->sr_text = "adding non-existing object "
                                                "as memberof";
                                        send_ldap_result( op, rs );
@@ -707,7 +713,18 @@ memberof_op_add( Operation *op, SlapReply *rs )
        }
 
        rc = SLAP_CB_CONTINUE;
-       
+
+       sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
+       sc->sc_private = sc+1;
+       sc->sc_response = memberof_res_add;
+       sc->sc_cleanup = memberof_cleanup;
+       mci = sc->sc_private;
+       mci->on = on;
+       mci->member = NULL;
+       mci->memberof = NULL;
+       sc->sc_next = op->o_callback;
+       op->o_callback = sc;
+
 done:;
        op->o_dn = save_dn;
        op->o_ndn = save_ndn;
@@ -722,13 +739,32 @@ memberof_op_delete( Operation *op, SlapReply *rs )
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
        memberof_t      *mo = (memberof_t *)on->on_bi.bi_private;
 
-       memberof_is_t   iswhat = MEMBEROF_IS_GROUP;
+       slap_callback *sc;
+       memberof_cbinfo_t *mci;
+       OpExtra         *oex;
+
+       LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
+               if ( oex->oe_key == (void *)&memberof )
+                       return SLAP_CB_CONTINUE;
+       }
 
+       sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
+       sc->sc_private = sc+1;
+       sc->sc_response = memberof_res_delete;
+       sc->sc_cleanup = memberof_cleanup;
+       mci = sc->sc_private;
+       mci->on = on;
+       mci->member = NULL;
+       mci->memberof = NULL;
+       mci->what = MEMBEROF_IS_GROUP;
        if ( MEMBEROF_REFINT( mo ) ) {
-               iswhat = MEMBEROF_IS_BOTH;
+               mci->what = MEMBEROF_IS_BOTH;
        }
 
-       memberof_isGroupOrMember( op, &iswhat );
+       memberof_isGroupOrMember( op, mci );
+
+       sc->sc_next = op->o_callback;
+       op->o_callback = sc;
 
        return SLAP_CB_CONTINUE;
 }
@@ -740,9 +776,16 @@ memberof_op_modify( Operation *op, SlapReply *rs )
        memberof_t      *mo = (memberof_t *)on->on_bi.bi_private;
 
        Modifications   **mlp, **mmlp = NULL;
-       int             rc = SLAP_CB_CONTINUE;
+       int             rc = SLAP_CB_CONTINUE, save_member = 0;
        struct berval   save_dn, save_ndn;
-       memberof_is_t   iswhat = MEMBEROF_IS_GROUP;
+       slap_callback *sc;
+       memberof_cbinfo_t *mci, mcis;
+       OpExtra         *oex;
+
+       LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
+               if ( oex->oe_key == (void *)&memberof )
+                       return SLAP_CB_CONTINUE;
+       }
 
        if ( MEMBEROF_REVERSE( mo ) ) {
                for ( mlp = &op->orm_modlist; *mlp; mlp = &(*mlp)->sml_next ) {
@@ -757,12 +800,13 @@ memberof_op_modify( Operation *op, SlapReply *rs )
 
        save_dn = op->o_dn;
        save_ndn = op->o_ndn;
+       mcis.on = on;
+       mcis.what = MEMBEROF_IS_GROUP;
 
-       if ( memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS
-               && ( iswhat & MEMBEROF_IS_GROUP ) )
+       if ( memberof_isGroupOrMember( op, &mcis ) == LDAP_SUCCESS
+               && ( mcis.what & MEMBEROF_IS_GROUP ) )
        {
                Modifications *ml;
-               int save_member = 0;
 
                for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
                        if ( ml->sml_desc == mo->mo_ad_member ) {
@@ -775,26 +819,12 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                        }
                }
 
-               if ( save_member ) {
-                       BerVarray       vals = NULL;
-
-                       op->o_dn = op->o_bd->be_rootdn;
-                       op->o_dn = op->o_bd->be_rootndn;
-                       op->o_bd->bd_info = (BackendInfo *)on->on_info;
-                       rc = backend_attribute( op, NULL, &op->o_req_ndn,
-                                       mo->mo_ad_member, &vals, ACL_READ );
-                       op->o_bd->bd_info = (BackendInfo *)on;
-                       if ( rc == LDAP_SUCCESS && vals != NULL ) {
-                               memberof_saved_member_set( op, &saved_member_vals, vals );
-                               ber_bvarray_free_x( vals, op->o_tmpmemctx );
-                       }
-               }
 
                if ( MEMBEROF_DANGLING_CHECK( mo )
                                && !get_relax( op ) )
                {
                        op->o_dn = op->o_bd->be_rootdn;
-                       op->o_dn = op->o_bd->be_rootndn;
+                       op->o_ndn = op->o_bd->be_rootndn;
                        op->o_bd->bd_info = (BackendInfo *)on->on_info;
                
                        assert( op->orm_modlist != NULL );
@@ -817,6 +847,12 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                        break;
                
                                case LDAP_MOD_REPLACE:
+                                       /* Handle this just like a delete (see above) */
+                                       if ( !ml->sml_values ) {
+                                               mlp = &ml->sml_next;
+                                               break;
+                                       }
                                case LDAP_MOD_ADD:
                                        /* NOTE: right now, the attributeType we use
                                         * for member must have a normalized value */
@@ -826,6 +862,10 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                                int             rc;
                                                Entry           *e;
                
+                                               /* ITS#6670 Ignore member pointing to this entry */
+                                               if ( dn_match( &ml->sml_nvalues[i], &save_ndn ))
+                                                       continue;
+
                                                if ( be_entry_get_rw( op, &ml->sml_nvalues[ i ],
                                                                NULL, NULL, 0, &e ) == LDAP_SUCCESS )
                                                {
@@ -834,7 +874,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                                }
                
                                                if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-                                                       rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+                                                       rc = rs->sr_err = mo->mo_dangling_err;
                                                        rs->sr_text = "adding non-existing object "
                                                                "as group member";
                                                        send_ldap_result( op, rs );
@@ -931,7 +971,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                                }
 
                                                if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-                                                       rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+                                                       rc = rs->sr_err = mo->mo_dangling_err;
                                                        rs->sr_text = "deleting non-existing object "
                                                                "as memberof";
                                                        send_ldap_result( op, rs );
@@ -1012,7 +1052,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                goto done2;
                        }
 
-                       if ( ml->sml_op == LDAP_MOD_DELETE ) {
+                       if ( ml->sml_op == LDAP_MOD_DELETE || !ml->sml_values ) {
                                break;
                        }
                        /* fall thru */
@@ -1037,12 +1077,16 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                        goto done2;
                                }
 
+                               /* ITS#6670 Ignore member pointing to this entry */
+                               if ( dn_match( &ml->sml_nvalues[i], &save_ndn ))
+                                       continue;
+
                                rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ],
                                                NULL, NULL, 0, &e );
                                op->o_bd->bd_info = (BackendInfo *)on;
                                if ( rc != LDAP_SUCCESS ) {
                                        if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-                                               rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+                                               rc = rs->sr_err = mo->mo_dangling_err;
                                                rs->sr_text = "adding non-existing object "
                                                        "as memberof";
                                                send_ldap_result( op, rs );
@@ -1115,6 +1159,28 @@ done2:;
                op->o_bd->bd_info = (BackendInfo *)on;
        }
 
+       sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
+       sc->sc_private = sc+1;
+       sc->sc_response = memberof_res_modify;
+       sc->sc_cleanup = memberof_cleanup;
+       mci = sc->sc_private;
+       mci->on = on;
+       mci->member = NULL;
+       mci->memberof = NULL;
+       mci->what = mcis.what;
+
+       if ( save_member ) {
+               op->o_dn = op->o_bd->be_rootdn;
+               op->o_ndn = op->o_bd->be_rootndn;
+               op->o_bd->bd_info = (BackendInfo *)on->on_info;
+               rc = backend_attribute( op, NULL, &op->o_req_ndn,
+                               mo->mo_ad_member, &mci->member, ACL_READ );
+               op->o_bd->bd_info = (BackendInfo *)on;
+       }
+
+       sc->sc_next = op->o_callback;
+       op->o_callback = sc;
+
        rc = SLAP_CB_CONTINUE;
 
 done:;
@@ -1125,34 +1191,68 @@ done:;
        return rc;
 }
 
+static int
+memberof_op_modrdn( Operation *op, SlapReply *rs )
+{
+       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       slap_callback *sc;
+       memberof_cbinfo_t *mci;
+       OpExtra         *oex;
+
+       LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
+               if ( oex->oe_key == (void *)&memberof )
+                       return SLAP_CB_CONTINUE;
+       }
+
+       sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
+       sc->sc_private = sc+1;
+       sc->sc_response = memberof_res_modrdn;
+       sc->sc_cleanup = memberof_cleanup;
+       mci = sc->sc_private;
+       mci->on = on;
+       mci->member = NULL;
+       mci->memberof = NULL;
+
+       sc->sc_next = op->o_callback;
+       op->o_callback = sc;
+
+       return SLAP_CB_CONTINUE;
+}
+
 /*
  * response callback that adds memberof values when a group is added.
  */
 static int
 memberof_res_add( Operation *op, SlapReply *rs )
 {
-       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       memberof_cbinfo_t *mci = op->o_callback->sc_private;
+       slap_overinst   *on = mci->on;
        memberof_t      *mo = (memberof_t *)on->on_bi.bi_private;
 
        int             i;
 
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               return SLAP_CB_CONTINUE;
+       }
+
        if ( MEMBEROF_REVERSE( mo ) ) {
                Attribute       *ma;
 
                ma = attr_find( op->ora_e->e_attrs, mo->mo_ad_memberof );
                if ( ma != NULL ) {
-                       Operation       op2 = *op;
-                       SlapReply       rs2 = { 0 };
-
                        /* relax is required to allow to add
                         * a non-existing member */
-                       op2.o_relax = SLAP_CONTROL_CRITICAL;
+                       op->o_relax = SLAP_CONTROL_CRITICAL;
 
                        for ( i = 0; !BER_BVISNULL( &ma->a_nvals[ i ] ); i++ ) {
                
+                               /* ITS#6670 Ignore member pointing to this entry */
+                               if ( dn_match( &ma->a_nvals[i], &op->o_req_ndn ))
+                                       continue;
+
                                /* the modification is attempted
                                 * with the original identity */
-                               (void)memberof_value_modify( &op2, &rs2,
+                               memberof_value_modify( op,
                                        &ma->a_nvals[ i ], mo->mo_ad_member,
                                        NULL, NULL, &op->o_req_dn, &op->o_req_ndn );
                        }
@@ -1167,7 +1267,11 @@ memberof_res_add( Operation *op, SlapReply *rs )
                                a = attrs_find( a->a_next, mo->mo_ad_member ) )
                {
                        for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
-                               (void)memberof_value_modify( op, rs,
+                               /* ITS#6670 Ignore member pointing to this entry */
+                               if ( dn_match( &a->a_nvals[i], &op->o_req_ndn ))
+                                       continue;
+
+                               memberof_value_modify( op,
                                                &a->a_nvals[ i ],
                                                mo->mo_ad_memberof,
                                                NULL, NULL,
@@ -1186,35 +1290,36 @@ memberof_res_add( Operation *op, SlapReply *rs )
 static int
 memberof_res_delete( Operation *op, SlapReply *rs )
 {
-       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       memberof_cbinfo_t *mci = op->o_callback->sc_private;
+       slap_overinst   *on = mci->on;
        memberof_t      *mo = (memberof_t *)on->on_bi.bi_private;
 
        BerVarray       vals;
        int             i;
 
-       vals = memberof_saved_member_get( op, &saved_member_vals );
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       vals = mci->member;
        if ( vals != NULL ) {
                for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                       (void)memberof_value_modify( op, rs,
+                       memberof_value_modify( op,
                                        &vals[ i ], mo->mo_ad_memberof,
                                        &op->o_req_dn, &op->o_req_ndn,
                                        NULL, NULL );
                }
-
-               ber_bvarray_free( vals );
        }
 
        if ( MEMBEROF_REFINT( mo ) ) {
-               vals = memberof_saved_member_get( op, &saved_memberof_vals );
+               vals = mci->memberof;
                if ( vals != NULL ) {
                        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                               (void)memberof_value_modify( op, rs,
+                               memberof_value_modify( op,
                                                &vals[ i ], mo->mo_ad_member,
                                                &op->o_req_dn, &op->o_req_ndn,
                                                NULL, NULL );
                        }
-
-                       ber_bvarray_free( vals );
                }
        }
 
@@ -1228,13 +1333,17 @@ memberof_res_delete( Operation *op, SlapReply *rs )
 static int
 memberof_res_modify( Operation *op, SlapReply *rs )
 {
-       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       memberof_cbinfo_t *mci = op->o_callback->sc_private;
+       slap_overinst   *on = mci->on;
        memberof_t      *mo = (memberof_t *)on->on_bi.bi_private;
 
        int             i, rc;
        Modifications   *ml, *mml = NULL;
        BerVarray       vals;
-       memberof_is_t   iswhat = MEMBEROF_IS_GROUP;
+
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               return SLAP_CB_CONTINUE;
+       }
 
        if ( MEMBEROF_REVERSE( mo ) ) {
                for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
@@ -1252,7 +1361,7 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                case LDAP_MOD_DELETE:
                        if ( vals != NULL ) {
                                for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                                       memberof_value_modify( op, rs,
+                                       memberof_value_modify( op,
                                                        &vals[ i ], mo->mo_ad_member,
                                                        &op->o_req_dn, &op->o_req_ndn,
                                                        NULL, NULL );
@@ -1269,7 +1378,7 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                        op->o_bd->bd_info = (BackendInfo *)on;
                        if ( rc == LDAP_SUCCESS ) {
                                for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                                       (void)memberof_value_modify( op, rs,
+                                       memberof_value_modify( op,
                                                        &vals[ i ], mo->mo_ad_member,
                                                        &op->o_req_dn, &op->o_req_ndn,
                                                        NULL, NULL );
@@ -1277,7 +1386,7 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                                ber_bvarray_free_x( vals, op->o_tmpmemctx );
                        }
 
-                       if ( ml->sml_op == LDAP_MOD_DELETE ) {
+                       if ( ml->sml_op == LDAP_MOD_DELETE || !mml->sml_values ) {
                                break;
                        }
                        /* fall thru */
@@ -1286,7 +1395,7 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                        assert( vals != NULL );
 
                        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                               memberof_value_modify( op, rs,
+                               memberof_value_modify( op,
                                                &vals[ i ], mo->mo_ad_member,
                                                NULL, NULL,
                                                &op->o_req_dn, &op->o_req_ndn );
@@ -1298,8 +1407,7 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                }
        }
 
-       if ( memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS
-                       && ( iswhat & MEMBEROF_IS_GROUP ) )
+       if ( mci->what & MEMBEROF_IS_GROUP )
        {
                for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
                        if ( ml->sml_desc != mo->mo_ad_member ) {
@@ -1311,7 +1419,7 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                                vals = ml->sml_nvalues;
                                if ( vals != NULL ) {
                                        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                                               memberof_value_modify( op, rs,
+                                               memberof_value_modify( op,
                                                                &vals[ i ], mo->mo_ad_memberof,
                                                                &op->o_req_dn, &op->o_req_ndn,
                                                                NULL, NULL );
@@ -1321,20 +1429,19 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                                /* fall thru */
        
                        case LDAP_MOD_REPLACE:
-                               vals = memberof_saved_member_get( op, &saved_member_vals );
+                               vals = mci->member;
 
                                /* delete all ... */
                                if ( vals != NULL ) {
                                        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                                               (void)memberof_value_modify( op, rs,
+                                               memberof_value_modify( op,
                                                                &vals[ i ], mo->mo_ad_memberof,
                                                                &op->o_req_dn, &op->o_req_ndn,
                                                                NULL, NULL );
                                        }
-                                       ber_bvarray_free_x( vals, op->o_tmpmemctx );
                                }
        
-                               if ( ml->sml_op == LDAP_MOD_DELETE ) {
+                               if ( ml->sml_op == LDAP_MOD_DELETE || !ml->sml_values ) {
                                        break;
                                }
                                /* fall thru */
@@ -1343,7 +1450,7 @@ memberof_res_modify( Operation *op, SlapReply *rs )
                                assert( ml->sml_nvalues != NULL );
                                vals = ml->sml_nvalues;
                                for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                                       memberof_value_modify( op, rs,
+                                       memberof_value_modify( op,
                                                        &vals[ i ], mo->mo_ad_memberof,
                                                        NULL, NULL,
                                                        &op->o_req_dn, &op->o_req_ndn );
@@ -1361,12 +1468,13 @@ memberof_res_modify( Operation *op, SlapReply *rs )
 
 /*
  * response callback that adds/deletes member values when a group member
- * is modified.
+ * is renamed.
  */
 static int
-memberof_res_rename( Operation *op, SlapReply *rs )
+memberof_res_modrdn( Operation *op, SlapReply *rs )
 {
-       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       memberof_cbinfo_t *mci = op->o_callback->sc_private;
+       slap_overinst   *on = mci->on;
        memberof_t      *mo = (memberof_t *)on->on_bi.bi_private;
 
        struct berval   newPDN, newDN = BER_BVNULL, newPNDN, newNDN;
@@ -1374,10 +1482,14 @@ memberof_res_rename( Operation *op, SlapReply *rs )
        BerVarray       vals;
 
        struct berval   save_dn, save_ndn;
-       memberof_is_t   iswhat = MEMBEROF_IS_GROUP;
 
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       mci->what = MEMBEROF_IS_GROUP;
        if ( MEMBEROF_REFINT( mo ) ) {
-               iswhat |= MEMBEROF_IS_MEMBER;
+               mci->what |= MEMBEROF_IS_MEMBER;
        }
 
        if ( op->orr_nnewSup ) {
@@ -1394,11 +1506,11 @@ memberof_res_rename( Operation *op, SlapReply *rs )
 
        op->o_req_dn = newNDN;
        op->o_req_ndn = newNDN;
-       rc = memberof_isGroupOrMember( op, &iswhat );
+       rc = memberof_isGroupOrMember( op, mci );
        op->o_req_dn = save_dn;
        op->o_req_ndn = save_ndn;
 
-       if ( rc != LDAP_SUCCESS || iswhat == MEMBEROF_IS_NONE ) {
+       if ( rc != LDAP_SUCCESS || mci->what == MEMBEROF_IS_NONE ) {
                goto done;
        }
 
@@ -1411,7 +1523,7 @@ memberof_res_rename( Operation *op, SlapReply *rs )
 
        build_new_dn( &newDN, &newPDN, &op->orr_newrdn, op->o_tmpmemctx ); 
 
-       if ( iswhat & MEMBEROF_IS_GROUP ) {
+       if ( mci->what & MEMBEROF_IS_GROUP ) {
                op->o_bd->bd_info = (BackendInfo *)on->on_info;
                rc = backend_attribute( op, NULL, &newNDN,
                                mo->mo_ad_member, &vals, ACL_READ );
@@ -1419,7 +1531,7 @@ memberof_res_rename( Operation *op, SlapReply *rs )
 
                if ( rc == LDAP_SUCCESS ) {
                        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                               (void)memberof_value_modify( op, rs,
+                               memberof_value_modify( op,
                                                &vals[ i ], mo->mo_ad_memberof,
                                                &op->o_req_dn, &op->o_req_ndn,
                                                &newDN, &newNDN );
@@ -1428,7 +1540,7 @@ memberof_res_rename( Operation *op, SlapReply *rs )
                }
        }
 
-       if ( MEMBEROF_REFINT( mo ) && ( iswhat & MEMBEROF_IS_MEMBER ) ) {
+       if ( MEMBEROF_REFINT( mo ) && ( mci->what & MEMBEROF_IS_MEMBER ) ) {
                op->o_bd->bd_info = (BackendInfo *)on->on_info;
                rc = backend_attribute( op, NULL, &newNDN,
                                mo->mo_ad_memberof, &vals, ACL_READ );
@@ -1436,7 +1548,7 @@ memberof_res_rename( Operation *op, SlapReply *rs )
 
                if ( rc == LDAP_SUCCESS ) {
                        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
-                               (void)memberof_value_modify( op, rs,
+                               memberof_value_modify( op,
                                                &vals[ i ], mo->mo_ad_member,
                                                &op->o_req_dn, &op->o_req_ndn,
                                                &newDN, &newNDN );
@@ -1454,30 +1566,6 @@ done:;
        return SLAP_CB_CONTINUE;
 }
 
-static int
-memberof_response( Operation *op, SlapReply *rs )
-{
-       if ( rs->sr_err != LDAP_SUCCESS ) {
-               return SLAP_CB_CONTINUE;
-       }
-
-       switch ( op->o_tag ) {
-       case LDAP_REQ_ADD:
-               return memberof_res_add( op, rs );
-
-       case LDAP_REQ_DELETE:
-               return memberof_res_delete( op, rs );
-
-       case LDAP_REQ_MODIFY:
-               return memberof_res_modify( op, rs );
-
-       case LDAP_REQ_MODDN:
-               return memberof_res_rename( op, rs );
-
-       default:
-               return SLAP_CB_CONTINUE;
-       }
-}
 
 static int
 memberof_db_init(
@@ -1485,9 +1573,13 @@ memberof_db_init(
        ConfigReply     *cr )
 {
        slap_overinst   *on = (slap_overinst *)be->bd_info;
-       memberof_t      tmp_mo = { 0 }, *mo;
+       memberof_t              *mo;
 
        mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) );
+
+       /* safe default */
+       mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION;
+
        on->on_bi.bi_private = (void *)mo;
 
        return 0;
@@ -1497,12 +1589,16 @@ enum {
        MO_DN = 1,
        MO_DANGLING,
        MO_REFINT,
+       MO_GROUP_OC,
+       MO_MEMBER_AD,
+       MO_MEMBER_OF_AD,
 #if 0
        MO_REVERSE,
 #endif
-       MO_GROUP_OC,
-       MO_MEMBER_AD,
-       MO_MEMBER_OF_AD
+
+       MO_DANGLING_ERROR,
+
+       MO_LAST
 };
 
 static ConfigDriver mo_cf_gen;
@@ -1568,6 +1664,13 @@ static ConfigTable mo_cfg[] = {
                NULL, NULL },
 #endif
 
+       { "memberof-dangling-error", "error code",
+               2, 2, 0, ARG_MAGIC|MO_DANGLING_ERROR, mo_cf_gen,
+               "( OLcfgOvAt:18.7 NAME 'olcMemberOfDanglingError' "
+                       "DESC 'Error code returned in case of dangling back reference' "
+                       "SYNTAX OMsDirectoryString SINGLE-VALUE )",
+               NULL, NULL },
+
        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
 };
 
@@ -1579,6 +1682,7 @@ static ConfigOCs mo_ocs[] = {
                "MAY ( "
                        "olcMemberOfDN "
                        "$ olcMemberOfDangling "
+                       "$ olcMemberOfDanglingError"
                        "$ olcMemberOfRefInt "
                        "$ olcMemberOfGroupOC "
                        "$ olcMemberOfMemberAD "
@@ -1681,6 +1785,25 @@ mo_cf_gen( ConfigArgs *c )
                        }
                        break;
 
+               case MO_DANGLING_ERROR:
+                       if ( mo->mo_flags & MEMBEROF_FDANGLING_ERROR ) {
+                               char buf[ SLAP_TEXT_BUFLEN ];
+                               enum_to_verb( slap_ldap_response_code, mo->mo_dangling_err, &bv );
+                               if ( BER_BVISNULL( &bv ) ) {
+                                       bv.bv_len = snprintf( buf, sizeof( buf ), "0x%x", mo->mo_dangling_err );
+                                       if ( bv.bv_len < sizeof( buf ) ) {
+                                               bv.bv_val = buf;
+                                       } else {
+                                               rc = 1;
+                                               break;
+                                       }
+                               }
+                               value_add_one( &c->rvalue_vals, &bv );
+                       } else {
+                               rc = 1;
+                       }
+                       break;
+
                case MO_REFINT:
                        c->value_int = MEMBEROF_REFINT( mo );
                        break;
@@ -1740,6 +1863,15 @@ mo_cf_gen( ConfigArgs *c )
                        mo->mo_flags |= dangling_mode[ i ].mask;
                        break;
 
+               case MO_DANGLING_ERROR:
+                       i = verb_to_mask( c->argv[ 1 ], slap_ldap_response_code );
+                       if ( !BER_BVISNULL( &slap_ldap_response_code[ i ].word ) ) {
+                               mo->mo_dangling_err = slap_ldap_response_code[ i ].mask;
+                       } else if ( lutil_atoix( &mo->mo_dangling_err, c->argv[ 1 ], 0 ) ) {
+                               return 1;
+                       }
+                       break;
+
                case MO_REFINT:
                        if ( c->value_int ) {
                                mo->mo_flags |= MEMBEROF_FREFINT;
@@ -1878,7 +2010,7 @@ memberof_db_open(
                }
        }
 
-    if( ! mo->mo_oc_group ){
+       if( ! mo->mo_oc_group ){
                mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS );
                if ( mo->mo_oc_group == NULL ) {
                        Debug( LDAP_DEBUG_ANY,
@@ -1889,7 +2021,7 @@ memberof_db_open(
                }
        }
 
-       if ( BER_BVISNULL( &mo->mo_dn ) ) {
+       if ( BER_BVISNULL( &mo->mo_dn ) && !BER_BVISNULL( &be->be_rootdn ) ) {
                ber_dupbv( &mo->mo_dn, &be->be_rootdn );
                ber_dupbv( &mo->mo_ndn, &be->be_rootndn );
        }
@@ -1979,8 +2111,7 @@ memberof_initialize( void )
        memberof.on_bi.bi_op_add = memberof_op_add;
        memberof.on_bi.bi_op_delete = memberof_op_delete;
        memberof.on_bi.bi_op_modify = memberof_op_modify;
-
-       memberof.on_response = memberof_response;
+       memberof.on_bi.bi_op_modrdn = memberof_op_modrdn;
 
        memberof.on_bi.bi_cf_ocs = mo_ocs;