]> git.sur5r.net Git - openldap/blobdiff - contrib/slapd-modules/autogroup/autogroup.c
ITS#6684
[openldap] / contrib / slapd-modules / autogroup / autogroup.c
index 1f6f4b680b24265c89becbe1194ba4f98919a310..29e4bc2ede586fa1cef90b07e680e2e8223861d0 100644 (file)
@@ -1,7 +1,10 @@
 /* autogroup.c - automatic group overlay */
 /* $OpenLDAP$ */
-/*
- * Copyright 2007 Michał Szulczyński.
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2007-2010 The OpenLDAP Foundation.
+ * Portions Copyright 2007 Michał Szulczyński.
+ * Portions Copyright 2009 Howard Chu.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Michał Szulczyński for inclusion in
+ * OpenLDAP Software.  Additional significant contributors include:
+ *   Howard Chu
+ */
 
 #include "portable.h"
 
@@ -30,6 +38,7 @@ typedef struct autogroup_filter_t {
        struct berval                   agf_filterstr;
        Filter                          *agf_filter;
        int                             agf_scope;
+       AttributeName                   *agf_anlist;
        struct autogroup_filter_t       *agf_next;
 } autogroup_filter_t;
 
@@ -48,6 +57,8 @@ typedef struct autogroup_entry_t {
        autogroup_filter_t      *age_filter; /* List of filters made from memberURLs */
        autogroup_def_t         *age_def; /* Attribute definition */
        ldap_pvt_thread_mutex_t age_mutex;
+       int                     age_mustrefresh; /* Defined in request to refresh in response */
+       int                     age_modrdn_olddnmodified; /* Defined in request to refresh in response */
        struct autogroup_entry_t        *age_next;
 } autogroup_entry_t;
 
@@ -67,6 +78,7 @@ typedef struct autogroup_sc_t {
 /* Used for adding members, found when searching, to a group. */
 typedef struct autogroup_ga_t {
        autogroup_entry_t       *agg_group;     /* The group to which the members will be added. */
+       autogroup_filter_t      *agg_filter;    /* Current filter */
        Entry                   *agg_entry;     /* Used in autogroup_member_search_cb to modify 
                                                this entry with the search results. */
 
@@ -86,9 +98,9 @@ static int
 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
 {
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
-       Modifications   modlist;
+       Modifications   *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
        SlapReply       sreply = {REP_RESULT};
-       BerValue        vals[ 2 ], nvals[ 2 ];
+       BerValue        *vals, *nvals;
        slap_callback   cb = { NULL, slap_null_cb, NULL, NULL };
        Operation       o = *op;
 
@@ -98,17 +110,71 @@ autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autog
        assert( dn != NULL );
        assert( ndn != NULL );
 
-       vals[ 0 ] = *dn;
+       vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
+       nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
+       ber_dupbv( vals, dn );
        BER_BVZERO( &vals[ 1 ] );
-       nvals[ 0 ] = *ndn;
+       ber_dupbv( nvals, ndn );
        BER_BVZERO( &nvals[ 1 ] );
 
+       modlist->sml_op = LDAP_MOD_ADD;
+       modlist->sml_desc = age->age_def->agd_member_ad;
+       modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
+       modlist->sml_values = vals;
+       modlist->sml_nvalues = nvals;
+       modlist->sml_numvals = 1;
+       modlist->sml_flags = SLAP_MOD_INTERNAL;
+       modlist->sml_next = NULL;
+
+       o.o_tag = LDAP_REQ_MODIFY;
+       o.o_callback = &cb;
+       o.orm_modlist = modlist;
+       o.o_req_dn = age->age_dn;
+       o.o_req_ndn = age->age_ndn;
+       o.o_permissive_modify = 1;
+       o.o_managedsait = SLAP_CONTROL_CRITICAL;
+       o.o_relax = SLAP_CONTROL_CRITICAL;
+
+       o.o_bd->bd_info = (BackendInfo *)on->on_info;
+       (void)op->o_bd->be_modify( &o, &sreply );
+       o.o_bd->bd_info = (BackendInfo *)on;
+
+       slap_mods_free( modlist, 1 );
+
+       return sreply.sr_err;
+}
+
+/* 
+**     e       - the entry where to get the attribute values
+**     age     - the group to which the values will be added
+*/
+static int
+autogroup_add_member_values_to_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc )
+{
+       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       Modifications   modlist;
+       SlapReply       sreply = {REP_RESULT};
+       Attribute       *attr;
+       slap_callback   cb = { NULL, slap_null_cb, NULL, NULL };
+       Operation       o = *op;
+
+       Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
+               e->e_name.bv_val, age->age_dn.bv_val, 0);
+
+       assert( e != NULL );
+
+       attr = attrs_find( e->e_attrs, attrdesc );
+       if (!attr) {
+               // Nothing to add
+               return LDAP_SUCCESS;
+       }
+
        modlist.sml_op = LDAP_MOD_ADD;
        modlist.sml_desc = age->age_def->agd_member_ad;
        modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
-       modlist.sml_values = vals;
-       modlist.sml_nvalues = nvals;
-       modlist.sml_numvals = 1;
+       modlist.sml_values = attr->a_vals;
+       modlist.sml_nvalues = attr->a_nvals;
+       modlist.sml_numvals = attr->a_numvals;
        modlist.sml_flags = SLAP_MOD_INTERNAL;
        modlist.sml_next = NULL;
 
@@ -137,9 +203,9 @@ static int
 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
 {
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
-       Modifications   modlist;
+       Modifications   *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
        SlapReply       sreply = {REP_RESULT};
-       BerValue        vals[ 2 ], nvals[ 2 ];
+       BerValue        *vals, *nvals;
        slap_callback   cb = { NULL, slap_null_cb, NULL, NULL };
        Operation       o = *op;
 
@@ -147,33 +213,35 @@ autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn,
                Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
                        age->age_dn.bv_val, 0 ,0);
 
-               modlist.sml_values = NULL;
-               modlist.sml_nvalues = NULL;
-               modlist.sml_numvals = 0;
+               modlist->sml_values = NULL;
+               modlist->sml_nvalues = NULL;
+               modlist->sml_numvals = 0;
        } else {
                Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
                        dn->bv_val, age->age_dn.bv_val, 0);
 
-               vals[ 0 ] = *dn;
+               vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
+               nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
+               ber_dupbv( vals, dn );
                BER_BVZERO( &vals[ 1 ] );
-               nvals[ 0 ] = *ndn;
+               ber_dupbv( nvals, ndn );
                BER_BVZERO( &nvals[ 1 ] );
 
-               modlist.sml_values = vals;
-               modlist.sml_nvalues = nvals;
-               modlist.sml_numvals = 1;
+               modlist->sml_values = vals;
+               modlist->sml_nvalues = nvals;
+               modlist->sml_numvals = 1;
        }
 
 
-       modlist.sml_op = LDAP_MOD_DELETE;
-       modlist.sml_desc = age->age_def->agd_member_ad;
-       modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
-       modlist.sml_flags = SLAP_MOD_INTERNAL;
-       modlist.sml_next = NULL;
+       modlist->sml_op = LDAP_MOD_DELETE;
+       modlist->sml_desc = age->age_def->agd_member_ad;
+       modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
+       modlist->sml_flags = SLAP_MOD_INTERNAL;
+       modlist->sml_next = NULL;
 
        o.o_callback = &cb;
        o.o_tag = LDAP_REQ_MODIFY;
-       o.orm_modlist = &modlist;
+       o.orm_modlist = modlist;
        o.o_req_dn = age->age_dn;
        o.o_req_ndn = age->age_ndn;
        o.o_relax = SLAP_CONTROL_CRITICAL;
@@ -184,6 +252,8 @@ autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn,
        (void)op->o_bd->be_modify( &o, &sreply );
        o.o_bd->bd_info = (BackendInfo *)on;
 
+       slap_mods_free( modlist, 1 );
+
        return sreply.sr_err;
 }
 
@@ -203,25 +273,43 @@ autogroup_member_search_cb( Operation *op, SlapReply *rs )
        if ( rs->sr_type == REP_SEARCH ) {
                autogroup_ga_t          *agg = (autogroup_ga_t *)op->o_callback->sc_private;
                autogroup_entry_t       *age = agg->agg_group;
+               autogroup_filter_t      *agf = agg->agg_filter;
                Modification            mod;
                const char              *text = NULL;
                char                    textbuf[1024];
-               struct berval           vals[ 2 ], nvals[ 2 ];
+               struct berval           *vals, *nvals;
+               int                     numvals;
 
                Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
                        rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
 
-               vals[ 0 ] = rs->sr_entry->e_name;
-               BER_BVZERO( &vals[ 1 ] );
-               nvals[ 0 ] = rs->sr_entry->e_nname;
-               BER_BVZERO( &nvals[ 1 ] );
+               if ( agf->agf_anlist ) {
+                       Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
+                       if (attr) {
+                               vals = attr->a_vals;
+                               nvals = attr->a_nvals;
+                               numvals = attr->a_numvals;
+                       } else {
+                               // Nothing to add
+                               return 0;
+                       }
+               } else {
+                       struct berval           lvals[ 2 ], lnvals[ 2 ];
+                       lvals[ 0 ] = rs->sr_entry->e_name;
+                       BER_BVZERO( &lvals[ 1 ] );
+                       lnvals[ 0 ] = rs->sr_entry->e_nname;
+                       BER_BVZERO( &lnvals[ 1 ] );
+                       vals = lvals;
+                       nvals = lnvals;
+                       numvals = 1;
+               }
 
                mod.sm_op = LDAP_MOD_ADD;
                mod.sm_desc = age->age_def->agd_member_ad;
                mod.sm_type = age->age_def->agd_member_ad->ad_cname;
                mod.sm_values = vals;
                mod.sm_nvalues = nvals;
-               mod.sm_numvals = 1;
+               mod.sm_numvals = numvals;
 
                modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
        }
@@ -238,48 +326,61 @@ autogroup_member_search_cb( Operation *op, SlapReply *rs )
 static int
 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
 {
-       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
-
        assert( op->o_tag == LDAP_REQ_SEARCH );
 
        if ( rs->sr_type == REP_SEARCH ) {
                autogroup_ga_t          *agg = (autogroup_ga_t *)op->o_callback->sc_private;
                autogroup_entry_t       *age = agg->agg_group;
-               Operation               o = *op;
+               autogroup_filter_t      *agf = agg->agg_filter;
                Modifications           *modlist;
-               SlapReply               sreply = {REP_RESULT};
-               const char              *text = NULL;
-               char                    textbuf[1024];
-               struct berval           vals[ 2 ], nvals[ 2 ];
-               slap_callback           cb = { NULL, slap_null_cb, NULL, NULL };
+               struct berval           *vals, *nvals;
+               int                     numvals;
 
                Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
                        rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
 
-               vals[ 0 ] = rs->sr_entry->e_name;
-               BER_BVZERO( &vals[ 1 ] );
-               nvals[ 0 ] = rs->sr_entry->e_nname;
-               BER_BVZERO( &nvals[ 1 ] );
+               if ( agf->agf_anlist ) {
+                       Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
+                       if (attr) {
+                               vals = attr->a_vals;
+                               nvals = attr->a_nvals;
+                               numvals = attr->a_numvals;
+                       } else {
+                               // Nothing to add
+                               return 0;
+                       }
+               } else {
+                       struct berval           lvals[ 2 ], lnvals[ 2 ];
+                       lvals[ 0 ] = rs->sr_entry->e_name;
+                       BER_BVZERO( &lvals[ 1 ] );
+                       lnvals[ 0 ] = rs->sr_entry->e_nname;
+                       BER_BVZERO( &lnvals[ 1 ] );
+                       vals = lvals;
+                       nvals = lnvals;
+                       numvals = 1;
+               }
 
-               modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
+               if ( numvals ) {
+                       modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
 
-               modlist->sml_op = LDAP_MOD_ADD;
-               modlist->sml_desc = age->age_def->agd_member_ad;
-               modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
+                       modlist->sml_op = LDAP_MOD_ADD;
+                       modlist->sml_desc = age->age_def->agd_member_ad;
+                       modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
 
-               ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
-               ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
-               modlist->sml_numvals = 1;
+                       ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
+                       ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
+                       modlist->sml_numvals = numvals;
 
-               modlist->sml_flags = SLAP_MOD_INTERNAL;
-               modlist->sml_next = NULL;
+                       modlist->sml_flags = SLAP_MOD_INTERNAL;
+                       modlist->sml_next = NULL;
 
-               if ( agg->agg_mod == NULL ) {
-                       agg->agg_mod = modlist;
-                       agg->agg_mod_last = modlist;
-               } else {
-                       agg->agg_mod_last->sml_next = modlist;
-                       agg->agg_mod_last = modlist;
+                       if ( agg->agg_mod == NULL ) {
+                               agg->agg_mod = modlist;
+                               agg->agg_mod_last = modlist;
+                       } else {
+                               agg->agg_mod_last->sml_next = modlist;
+                               agg->agg_mod_last = modlist;
+                       }
                }
 
        }
@@ -324,9 +425,10 @@ autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *a
        o.ors_limit = NULL;
        o.ors_tlimit = SLAP_NO_LIMIT;
        o.ors_slimit = SLAP_NO_LIMIT;
-       o.ors_attrs =  slap_anlist_no_attrs;
+       o.ors_attrs =  agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
 
        agg.agg_group = age;
+       agg.agg_filter = agf;
        agg.agg_mod = NULL;
        agg.agg_mod_last = NULL;
        agg.agg_entry = e;
@@ -347,7 +449,7 @@ autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *a
        op->o_bd->be_search( &o, &rs );
        o.o_bd->bd_info = (BackendInfo *)on;    
 
-       if ( modify == 1 ) {
+       if ( modify == 1 && agg.agg_mod ) {
                o = *op;
                o.o_callback = &null_cb;
                o.o_tag = LDAP_REQ_MODIFY;
@@ -418,6 +520,8 @@ autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd,
        ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
        (*agep)->age_def = agd;
        (*agep)->age_filter = NULL;
+       (*agep)->age_mustrefresh = 0;
+       (*agep)->age_modrdn_olddnmodified = 0;
 
        ber_dupbv( &(*agep)->age_dn, &e->e_name );
        ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
@@ -463,6 +567,33 @@ autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd,
                                agf->agf_filter = str2filter( lud->lud_filter );
                        }                       
 
+                       if ( lud->lud_attrs != NULL ) {
+                               int i;
+
+                               for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
+                                       /* Just counting */;
+                               }
+
+                               if ( i > 1 ) {
+                                       Debug( LDAP_DEBUG_ANY, "autogroup_add_group: to much attributes specified in url <%s>\n",
+                                               bv->bv_val, 0, 0);
+                                       /* FIXME: error? */
+                                       ldap_free_urldesc( lud );
+                                       ch_free( agf ); 
+                               }
+                                       
+                               agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
+
+                               if ( agf->agf_anlist == NULL ) {
+                                       Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
+                                               lud->lud_attrs[0], 0, 0 );              
+                                       /* FIXME: error? */
+                                       ldap_free_urldesc( lud );
+                                       ch_free( agf ); 
+                                       continue;
+                               }
+                       }
+
                        agf->agf_next = NULL;
 
 
@@ -508,11 +639,8 @@ cleanup:;
 static int
 autogroup_group_add_cb( Operation *op, SlapReply *rs )
 {
-       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
-
        assert( op->o_tag == LDAP_REQ_SEARCH );
 
-
        if ( rs->sr_type == REP_SEARCH ) {
                autogroup_sc_t          *ags = (autogroup_sc_t *)op->o_callback->sc_private;
 
@@ -538,7 +666,6 @@ autogroup_add_entry( Operation *op, SlapReply *rs)
        autogroup_def_t         *agd = agi->agi_def;
        autogroup_entry_t       *age = agi->agi_entry;
        autogroup_filter_t      *agf;
-       Attribute               *a;
        int                     rc = 0;
 
        Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n", 
@@ -578,7 +705,11 @@ autogroup_add_entry( Operation *op, SlapReply *rs)
                        if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
                                rc = test_filter( op, op->ora_e, agf->agf_filter );
                                if ( rc == LDAP_COMPARE_TRUE ) {
-                               autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
+                                       if ( agf->agf_anlist ) {
+                                               autogroup_add_member_values_to_group( op, op->ora_e, age, agf->agf_anlist[0].an_desc );
+                                       } else {
+                                               autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
+                                       }
                                        break;
                                }
                        }
@@ -629,6 +760,8 @@ autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
                                ch_free( agf->agf_filterstr.bv_val );
                                ch_free( agf->agf_dn.bv_val );
                                ch_free( agf->agf_ndn.bv_val );
+                               anlist_free( agf->agf_anlist, 1, NULL );
+                               ch_free( agf );
                        }
 
                        ldap_pvt_thread_mutex_unlock( &age->age_mutex );                
@@ -652,7 +785,6 @@ autogroup_delete_entry( Operation *op, SlapReply *rs)
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        autogroup_info_t                *agi = (autogroup_info_t *)on->on_bi.bi_private;
-       autogroup_def_t         *agd = agi->agi_def;
        autogroup_entry_t       *age = agi->agi_entry,
                                *age_prev, *age_next;
        autogroup_filter_t      *agf;
@@ -683,9 +815,6 @@ autogroup_delete_entry( Operation *op, SlapReply *rs)
                        dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
 
                        if ( match == 0 ) {
-                               autogroup_filter_t      *agf = age->age_filter,
-                                                       *agf_next;
-
                                autogroup_delete_group( agi, age );
                                break;
                        }
@@ -710,7 +839,16 @@ autogroup_delete_entry( Operation *op, SlapReply *rs)
                        if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
                                rc = test_filter( op, e, agf->agf_filter );
                                if ( rc == LDAP_COMPARE_TRUE ) {
-                               autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
+                                       /* If the attribute is retrieved from the entry, we don't know what to delete
+                                       ** So the group must be entirely refreshed
+                                       ** But the refresh can't be done now because the entry is not deleted
+                                       ** So the group is marked as mustrefresh
+                                       */
+                                       if ( agf->agf_anlist ) {
+                                               age->age_mustrefresh = 1;
+                                       } else {
+                                               autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
+                                       }
                                        break;
                                }
                        }
@@ -735,8 +873,33 @@ autogroup_response( Operation *op, SlapReply *rs )
        BerValue                new_dn, new_ndn, pdn;
        Entry                   *e, *group;
        Attribute               *a;
-       int                     is_olddn, is_newdn, dn_equal;
+       int                     is_olddn, is_newdn, is_value_refresh, dn_equal;
+
+       /* Handle all cases where a refresh of the group is needed */
+       if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
+               if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
+
+                       ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
+
+                       for ( age = agi->agi_entry ; age ; age = age->age_next ) {
+                               /* Request detected that the group must be refreshed */
+
+                               ldap_pvt_thread_mutex_lock( &age->age_mutex );
+
+                               if ( age->age_mustrefresh ) {
+                                       autogroup_delete_member_from_group( op, NULL, NULL, age) ;
+
+                                       for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
+                                               autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
+                                       }
+                               }
+
+                               ldap_pvt_thread_mutex_unlock( &age->age_mutex );
+                       }
 
+                       ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
+               }
+       }
        if ( op->o_tag == LDAP_REQ_MODRDN ) {
                if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
 
@@ -824,45 +987,68 @@ autogroup_response( Operation *op, SlapReply *rs )
                        for ( age = agi->agi_entry ; age ; age = age->age_next ) {
                                is_olddn = 0;
                                is_newdn = 0;
+                               is_value_refresh = 0;
 
 
                                ldap_pvt_thread_mutex_lock( &age->age_mutex );
 
-                               if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
-                                       LDAP_SUCCESS || group == NULL ) {
-                                       Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
+                               if ( age->age_modrdn_olddnmodified ) {
+                                       /* Resquest already marked this group to be updated */
+                                       is_olddn = 1;
+                                       is_value_refresh = 1;
+                                       age->age_modrdn_olddnmodified = 0;
+                               } else {
 
-                                       op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
-                                       op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
+                                       if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
+                                               LDAP_SUCCESS || group == NULL ) {
+                                               Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
 
-                                       ldap_pvt_thread_mutex_unlock( &age->age_mutex );
-                                       ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
-                                       return SLAP_CB_CONTINUE;
-                               }
+                                               op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
+                                               op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
 
-                               a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
+                                               ldap_pvt_thread_mutex_unlock( &age->age_mutex );
+                                               ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
+                                               return SLAP_CB_CONTINUE;
+                                       }
+
+                                       a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
+
+                                       if ( a != NULL ) {
+                                               if ( value_find_ex( age->age_def->agd_member_ad,
+                                                               SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
+                                                               SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
+                                                               a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) 
+                                               {
+                                                       is_olddn = 1;
+                                               }
 
-                               if ( a != NULL ) {
-                                       if ( value_find_ex( age->age_def->agd_member_ad,
-                                                       SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
-                                                       SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
-                                                       a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) 
-                                       {
-                                               is_olddn = 1;
                                        }
 
-                               }
+                                       overlay_entry_release_ov( op, group, 0, on );
 
-                               overlay_entry_release_ov( op, group, 0, on );
+                               }
 
                                for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
                                        if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
+                                               /* TODO: should retest filter as it could imply conditions on the dn */
                                                is_newdn = 1;
                                                break;
                                        }
                                }
 
 
+                               if ( is_value_refresh ) {
+                                       if ( is_olddn != is_newdn ) {
+                                               /* group refresh */
+                                               autogroup_delete_member_from_group( op, NULL, NULL, age) ;
+
+                                               for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
+                                                       autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
+                                               }
+                                       }
+                                       ldap_pvt_thread_mutex_unlock( &age->age_mutex );
+                                       continue;
+                               }
                                if ( is_olddn == 1 && is_newdn == 0 ) {
                                        autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
                                } else
@@ -928,7 +1114,7 @@ autogroup_response( Operation *op, SlapReply *rs )
 
                                        m = op->orm_modlist;
 
-                                       for ( ; age ; age = age->age_next ) {
+                                       for ( age = agi->agi_entry ; age ; age = age->age_next ) {
                                                ldap_pvt_thread_mutex_lock( &age->age_mutex );
 
                                                dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
@@ -1009,7 +1195,7 @@ autogroup_response( Operation *op, SlapReply *rs )
                                overlay_entry_release_ov( op, group, 0, on );
 
                                for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
-                                       if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
+                                       if ( !agf->agf_anlist && dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
                                                if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
                                                        is_newdn = 1;
                                                        break;
@@ -1062,6 +1248,26 @@ autogroup_modify_entry( Operation *op, SlapReply *rs)
                return SLAP_CB_CONTINUE;
        }
 
+       /* Must refresh groups if a matching member value is modified */
+       for ( ; age ; age = age->age_next ) {
+               autogroup_filter_t      *agf;
+               for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
+                       if ( agf->agf_anlist ) {
+                               Modifications   *m;
+                               for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
+                                       if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
+                                               if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
+                                                       int rc = test_filter( op, e, agf->agf_filter );
+                                                       if ( rc == LDAP_COMPARE_TRUE ) {
+                                                               age->age_mustrefresh = 1;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
        a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
 
        if ( a == NULL ) {
@@ -1084,7 +1290,7 @@ autogroup_modify_entry( Operation *op, SlapReply *rs)
 
                        m = op->orm_modlist;
 
-                       for ( ; age ; age = age->age_next ) {
+                       for ( age = agi->agi_entry ; age ; age = age->age_next ) {
                                dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
 
                                if ( match == 0 ) {
@@ -1112,6 +1318,51 @@ autogroup_modify_entry( Operation *op, SlapReply *rs)
        return SLAP_CB_CONTINUE;
 }
 
+/*
+** Detect if the olddn is part of a group and so if the group should be refreshed
+*/
+static int
+autogroup_modrdn_entry( Operation *op, SlapReply *rs)
+{
+       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
+       autogroup_info_t                *agi = (autogroup_info_t *)on->on_bi.bi_private;
+       autogroup_entry_t       *age = agi->agi_entry;
+       Entry                   *e;
+
+       if ( get_manageDSAit( op ) ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
+       ldap_pvt_thread_mutex_lock( &agi->agi_mutex );                  
+
+       if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
+               LDAP_SUCCESS || e == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
+               ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
+               return SLAP_CB_CONTINUE;
+       }
+
+       /* Must check if a dn is modified */
+       for ( ; age ; age = age->age_next ) {
+               autogroup_filter_t      *agf;
+               for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
+                       if ( agf->agf_anlist ) {
+                               if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
+                                       int rc = test_filter( op, e, agf->agf_filter );
+                                       if ( rc == LDAP_COMPARE_TRUE ) {
+                                               age->age_modrdn_olddnmodified = 1;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       overlay_entry_release_ov( op, e, 0, on );
+       ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );                        
+       return SLAP_CB_CONTINUE;
+}
+
 /* 
 ** Builds a filter for searching for the 
 ** group entries, according to the objectClass. 
@@ -1249,6 +1500,8 @@ ag_cfgen( ConfigArgs *c )
                                        ch_free( agf->agf_filterstr.bv_val );
                                        ch_free( agf->agf_dn.bv_val );
                                        ch_free( agf->agf_ndn.bv_val );
+                                       anlist_free( agf->agf_anlist, 1, NULL );
+                                       ch_free( agf );
                                }
 
                                ldap_pvt_thread_mutex_init( &age->age_mutex );
@@ -1266,7 +1519,6 @@ ag_cfgen( ConfigArgs *c )
                        autogroup_entry_t       *age_next, *age_prev;
                        autogroup_filter_t      *agf,
                                                *agf_next;
-                       struct berval           *bv;
 
                        ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
 
@@ -1297,6 +1549,8 @@ ag_cfgen( ConfigArgs *c )
                                                ch_free( agf->agf_filterstr.bv_val );
                                                ch_free( agf->agf_dn.bv_val );
                                                ch_free( agf->agf_ndn.bv_val );
+                                               anlist_free( agf->agf_anlist, 1, NULL );
+                                               ch_free( agf );
                                        }
 
                                        ldap_pvt_thread_mutex_destroy( &age->age_mutex );
@@ -1446,8 +1700,7 @@ autogroup_db_open(
        BackendDB       *be,
        ConfigReply     *cr )
 {
-       slap_overinst                   *on = (slap_overinst *) be->bd_info,
-                               *on_bd;
+       slap_overinst                   *on = (slap_overinst *) be->bd_info;
        autogroup_info_t                *agi = on->on_bi.bi_private;
        autogroup_def_t         *agd;
        autogroup_sc_t          ags;
@@ -1458,12 +1711,13 @@ autogroup_db_open(
        void                            *thrctx = ldap_pvt_thread_pool_context();
        Connection                      conn = { 0 };
        OperationBuffer         opbuf;
-       BerValue                bv;
-       char                    *ptr;
-       int                     rc = 0;
 
        Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
 
+       if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
+               return 0;
+       }
+
        connection_fake_init( &conn, &opbuf, thrctx );
        op = &opbuf.ob_op;
 
@@ -1482,31 +1736,28 @@ autogroup_db_open(
        op->ors_slimit = SLAP_NO_LIMIT;
        op->ors_attrs =  slap_anlist_no_attrs;
 
-       op->o_bd = select_backend(&op->o_req_ndn, 0);
+       op->o_bd = be;
+       op->o_bd->bd_info = (BackendInfo *)on->on_info;
+
+       ags.ags_info = agi;
+       cb.sc_private = &ags;
+       cb.sc_response = autogroup_group_add_cb;
+       cb.sc_cleanup = NULL;
+       cb.sc_next = NULL;
+
+       op->o_callback = &cb;
 
-       ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
        for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
 
                autogroup_build_def_filter(agd, op);
 
-
-               ags.ags_info = agi;
                ags.ags_def = agd;
-               cb.sc_private = &ags;
-               cb.sc_response = autogroup_group_add_cb;
-               cb.sc_cleanup = NULL;
-               cb.sc_next = NULL;
-
-               op->o_callback = &cb;
 
-               op->o_bd->bd_info = (BackendInfo *)on->on_info;
                op->o_bd->be_search( op, &rs );
-               op->o_bd->bd_info = (BackendInfo *)on;
 
-               filter_free_x( op, op->ors_filter );
+               filter_free_x( op, op->ors_filter, 1 );
                op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
        }               
-       ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
 
        return 0;
 }
@@ -1541,6 +1792,7 @@ autogroup_db_close(
                                ch_free( agf->agf_filterstr.bv_val );
                                ch_free( agf->agf_dn.bv_val );
                                ch_free( agf->agf_ndn.bv_val ); 
+                               anlist_free( agf->agf_anlist, 1, NULL );
                                ch_free( agf );
                        }
 
@@ -1595,6 +1847,7 @@ autogroup_initialize(void)
        autogroup.on_bi.bi_op_add = autogroup_add_entry;
        autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
        autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
+       autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
 
        autogroup.on_response = autogroup_response;