Home | History | Annotate | Line # | Download | only in autogroup
autogroup.c revision 1.1.1.5
      1  1.1.1.2     lukem /*	$NetBSD: autogroup.c,v 1.1.1.5 2017/02/09 01:46:42 christos Exp $	*/
      2  1.1.1.2     lukem 
      3      1.1     lukem /* autogroup.c - automatic group overlay */
      4  1.1.1.4      tron /* $OpenLDAP$ */
      5  1.1.1.2     lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  1.1.1.2     lukem  *
      7  1.1.1.5  christos  * Copyright 2007-2016 The OpenLDAP Foundation.
      8  1.1.1.2     lukem  * Portions Copyright 2007 Micha Szulczyski.
      9  1.1.1.2     lukem  * Portions Copyright 2009 Howard Chu.
     10      1.1     lukem  * All rights reserved.
     11      1.1     lukem  *
     12      1.1     lukem  * Redistribution and use in source and binary forms, with or without
     13      1.1     lukem  * modification, are permitted only as authorized by the OpenLDAP
     14      1.1     lukem  * Public License.
     15      1.1     lukem  *
     16      1.1     lukem  * A copy of this license is available in the file LICENSE in the
     17      1.1     lukem  * top-level directory of the distribution or, alternatively, at
     18      1.1     lukem  * <http://www.OpenLDAP.org/license.html>.
     19      1.1     lukem  */
     20  1.1.1.2     lukem /* ACKNOWLEDGEMENTS:
     21  1.1.1.2     lukem  * This work was initially developed by Micha Szulczyski for inclusion in
     22  1.1.1.2     lukem  * OpenLDAP Software.  Additional significant contributors include:
     23  1.1.1.2     lukem  *   Howard Chu
     24  1.1.1.4      tron  *   Raphael Ouazana
     25  1.1.1.4      tron  *   Norbert Pueschel
     26  1.1.1.4      tron  *   Christian Manal
     27  1.1.1.2     lukem  */
     28      1.1     lukem 
     29  1.1.1.5  christos #include <sys/cdefs.h>
     30  1.1.1.5  christos __RCSID("$NetBSD: autogroup.c,v 1.1.1.5 2017/02/09 01:46:42 christos Exp $");
     31  1.1.1.5  christos 
     32      1.1     lukem #include "portable.h"
     33      1.1     lukem 
     34      1.1     lukem #include <stdio.h>
     35      1.1     lukem 
     36      1.1     lukem #include <ac/string.h>
     37      1.1     lukem 
     38      1.1     lukem #include "slap.h"
     39      1.1     lukem #include "config.h"
     40      1.1     lukem #include "lutil.h"
     41      1.1     lukem 
     42  1.1.1.4      tron #ifndef SLAPD_MEMBEROF_ATTR
     43  1.1.1.4      tron #define	SLAPD_MEMBEROF_ATTR	"memberOf"
     44  1.1.1.4      tron #endif
     45  1.1.1.4      tron 
     46  1.1.1.5  christos static slap_overinst	autogroup;
     47  1.1.1.5  christos 
     48      1.1     lukem /* Filter represents the memberURL of a group. */
     49      1.1     lukem typedef struct autogroup_filter_t {
     50      1.1     lukem 	struct berval			agf_dn;	/* The base DN in memberURL */
     51      1.1     lukem 	struct berval			agf_ndn;
     52      1.1     lukem 	struct berval			agf_filterstr;
     53      1.1     lukem 	Filter				*agf_filter;
     54      1.1     lukem 	int				agf_scope;
     55  1.1.1.4      tron 	AttributeName			*agf_anlist;
     56      1.1     lukem 	struct autogroup_filter_t	*agf_next;
     57      1.1     lukem } autogroup_filter_t;
     58      1.1     lukem 
     59      1.1     lukem /* Description of group attributes. */
     60      1.1     lukem typedef struct autogroup_def_t {
     61      1.1     lukem 	ObjectClass		*agd_oc;
     62      1.1     lukem 	AttributeDescription	*agd_member_url_ad;
     63      1.1     lukem 	AttributeDescription	*agd_member_ad;
     64      1.1     lukem 	struct autogroup_def_t	*agd_next;
     65      1.1     lukem } autogroup_def_t;
     66      1.1     lukem 
     67      1.1     lukem /* Represents the group entry. */
     68      1.1     lukem typedef struct autogroup_entry_t {
     69      1.1     lukem 	BerValue		age_dn;
     70      1.1     lukem 	BerValue		age_ndn;
     71      1.1     lukem 	autogroup_filter_t	*age_filter; /* List of filters made from memberURLs */
     72      1.1     lukem 	autogroup_def_t		*age_def; /* Attribute definition */
     73      1.1     lukem 	ldap_pvt_thread_mutex_t age_mutex;
     74  1.1.1.4      tron 	int			age_mustrefresh; /* Defined in request to refresh in response */
     75  1.1.1.4      tron 	int			age_modrdn_olddnmodified; /* Defined in request to refresh in response */
     76      1.1     lukem 	struct autogroup_entry_t	*age_next;
     77      1.1     lukem } autogroup_entry_t;
     78      1.1     lukem 
     79      1.1     lukem /* Holds pointers to attribute definitions and groups. */
     80      1.1     lukem typedef struct autogroup_info_t {
     81      1.1     lukem 	autogroup_def_t		*agi_def;	/* Group attributes definitions. */
     82      1.1     lukem 	autogroup_entry_t	*agi_entry;	/* Group entries.  */
     83  1.1.1.4      tron 	AttributeDescription	*agi_memberof_ad;	/* memberOf attribute description  */
     84      1.1     lukem 	ldap_pvt_thread_mutex_t agi_mutex;
     85      1.1     lukem } autogroup_info_t;
     86      1.1     lukem 
     87      1.1     lukem /* Search callback for adding groups initially. */
     88      1.1     lukem typedef struct autogroup_sc_t {
     89      1.1     lukem 	autogroup_info_t		*ags_info;	/* Group definitions and entries.  */
     90      1.1     lukem 	autogroup_def_t		*ags_def;	/* Attributes definition of the group being added. */
     91      1.1     lukem } autogroup_sc_t;
     92      1.1     lukem 
     93      1.1     lukem /* Used for adding members, found when searching, to a group. */
     94      1.1     lukem typedef struct autogroup_ga_t {
     95      1.1     lukem 	autogroup_entry_t	*agg_group;	/* The group to which the members will be added. */
     96  1.1.1.4      tron 	autogroup_filter_t	*agg_filter;	/* Current filter */
     97      1.1     lukem 	Entry			*agg_entry;	/* Used in autogroup_member_search_cb to modify
     98      1.1     lukem 						this entry with the search results. */
     99      1.1     lukem 
    100      1.1     lukem 	Modifications		*agg_mod;	/* Used in autogroup_member_search_modify_cb to hold the
    101      1.1     lukem 						search results which will be added to the group. */
    102      1.1     lukem 
    103      1.1     lukem 	Modifications		*agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
    104      1.1     lukem 						have to search for the last mod added. */
    105      1.1     lukem } autogroup_ga_t;
    106      1.1     lukem 
    107      1.1     lukem 
    108      1.1     lukem /*
    109      1.1     lukem **	dn, ndn	- the DN of the member to add
    110      1.1     lukem **	age	- the group to which the member DN will be added
    111      1.1     lukem */
    112      1.1     lukem static int
    113      1.1     lukem autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
    114      1.1     lukem {
    115      1.1     lukem 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    116  1.1.1.4      tron 	Modifications	*modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
    117      1.1     lukem 	SlapReply	sreply = {REP_RESULT};
    118  1.1.1.4      tron 	BerValue	*vals, *nvals;
    119      1.1     lukem 	slap_callback	cb = { NULL, slap_null_cb, NULL, NULL };
    120      1.1     lukem 	Operation	o = *op;
    121  1.1.1.5  christos 	unsigned long opid = op->o_opid;
    122  1.1.1.5  christos 	OpExtra oex;
    123      1.1     lukem 
    124      1.1     lukem 	assert( dn != NULL );
    125      1.1     lukem 	assert( ndn != NULL );
    126  1.1.1.4      tron 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
    127  1.1.1.4      tron 		dn->bv_val, age->age_dn.bv_val, 0);
    128      1.1     lukem 
    129  1.1.1.4      tron 	vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    130  1.1.1.4      tron 	nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    131  1.1.1.4      tron 	ber_dupbv( vals, dn );
    132      1.1     lukem 	BER_BVZERO( &vals[ 1 ] );
    133  1.1.1.4      tron 	ber_dupbv( nvals, ndn );
    134      1.1     lukem 	BER_BVZERO( &nvals[ 1 ] );
    135      1.1     lukem 
    136  1.1.1.4      tron 	modlist->sml_op = LDAP_MOD_ADD;
    137  1.1.1.4      tron 	modlist->sml_desc = age->age_def->agd_member_ad;
    138  1.1.1.4      tron 	modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
    139  1.1.1.4      tron 	modlist->sml_values = vals;
    140  1.1.1.4      tron 	modlist->sml_nvalues = nvals;
    141  1.1.1.4      tron 	modlist->sml_numvals = 1;
    142  1.1.1.4      tron 	modlist->sml_flags = SLAP_MOD_INTERNAL;
    143  1.1.1.4      tron 	modlist->sml_next = NULL;
    144  1.1.1.4      tron 
    145  1.1.1.5  christos 	o.o_opid = 0;	/* shared with op, saved above */
    146  1.1.1.4      tron 	o.o_tag = LDAP_REQ_MODIFY;
    147  1.1.1.4      tron 	o.o_callback = &cb;
    148  1.1.1.4      tron 	o.orm_modlist = modlist;
    149  1.1.1.5  christos 	o.o_dn = op->o_bd->be_rootdn;
    150  1.1.1.5  christos 	o.o_ndn = op->o_bd->be_rootndn;
    151  1.1.1.4      tron 	o.o_req_dn = age->age_dn;
    152  1.1.1.4      tron 	o.o_req_ndn = age->age_ndn;
    153  1.1.1.4      tron 	o.o_permissive_modify = 1;
    154  1.1.1.5  christos 	o.o_dont_replicate = 1;
    155  1.1.1.5  christos 	o.orm_no_opattrs = 1;
    156  1.1.1.4      tron 	o.o_managedsait = SLAP_CONTROL_CRITICAL;
    157  1.1.1.4      tron 	o.o_relax = SLAP_CONTROL_CRITICAL;
    158  1.1.1.4      tron 
    159  1.1.1.5  christos 	oex.oe_key = (void *)&autogroup;
    160  1.1.1.5  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    161  1.1.1.5  christos 
    162  1.1.1.4      tron 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    163  1.1.1.4      tron 	(void)op->o_bd->be_modify( &o, &sreply );
    164  1.1.1.4      tron 	o.o_bd->bd_info = (BackendInfo *)on;
    165  1.1.1.4      tron 
    166  1.1.1.5  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    167  1.1.1.5  christos 
    168  1.1.1.4      tron 	slap_mods_free( modlist, 1 );
    169  1.1.1.5  christos 	op->o_opid = opid;
    170  1.1.1.4      tron 
    171  1.1.1.4      tron 	return sreply.sr_err;
    172  1.1.1.4      tron }
    173  1.1.1.4      tron 
    174  1.1.1.4      tron /*
    175  1.1.1.4      tron **	e	- the entry where to get the attribute values
    176  1.1.1.4      tron **	age	- the group to which the values will be added
    177  1.1.1.4      tron */
    178  1.1.1.4      tron static int
    179  1.1.1.5  christos autogroup_add_member_values_to_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
    180  1.1.1.4      tron {
    181  1.1.1.4      tron 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    182  1.1.1.4      tron 	Modifications	modlist;
    183  1.1.1.4      tron 	SlapReply	sreply = {REP_RESULT};
    184  1.1.1.4      tron 	slap_callback	cb = { NULL, slap_null_cb, NULL, NULL };
    185  1.1.1.4      tron 	Operation	o = *op;
    186  1.1.1.5  christos 	unsigned long opid = op->o_opid;
    187  1.1.1.5  christos 	OpExtra oex;
    188  1.1.1.4      tron 
    189  1.1.1.4      tron 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
    190  1.1.1.5  christos 		dn->bv_val, age->age_dn.bv_val, 0);
    191  1.1.1.4      tron 
    192      1.1     lukem 	modlist.sml_op = LDAP_MOD_ADD;
    193      1.1     lukem 	modlist.sml_desc = age->age_def->agd_member_ad;
    194      1.1     lukem 	modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
    195  1.1.1.4      tron 	modlist.sml_values = attr->a_vals;
    196  1.1.1.4      tron 	modlist.sml_nvalues = attr->a_nvals;
    197  1.1.1.4      tron 	modlist.sml_numvals = attr->a_numvals;
    198      1.1     lukem 	modlist.sml_flags = SLAP_MOD_INTERNAL;
    199      1.1     lukem 	modlist.sml_next = NULL;
    200      1.1     lukem 
    201  1.1.1.5  christos 	o.o_opid = 0;
    202      1.1     lukem 	o.o_tag = LDAP_REQ_MODIFY;
    203      1.1     lukem 	o.o_callback = &cb;
    204      1.1     lukem 	o.orm_modlist = &modlist;
    205  1.1.1.5  christos 	o.o_dn = op->o_bd->be_rootdn;
    206  1.1.1.5  christos 	o.o_ndn = op->o_bd->be_rootndn;
    207      1.1     lukem 	o.o_req_dn = age->age_dn;
    208      1.1     lukem 	o.o_req_ndn = age->age_ndn;
    209      1.1     lukem 	o.o_permissive_modify = 1;
    210  1.1.1.5  christos 	o.o_dont_replicate = 1;
    211  1.1.1.5  christos 	o.orm_no_opattrs = 1;
    212      1.1     lukem 	o.o_managedsait = SLAP_CONTROL_CRITICAL;
    213      1.1     lukem 	o.o_relax = SLAP_CONTROL_CRITICAL;
    214      1.1     lukem 
    215  1.1.1.5  christos 	oex.oe_key = (void *)&autogroup;
    216  1.1.1.5  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    217  1.1.1.5  christos 
    218      1.1     lukem 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    219      1.1     lukem 	(void)op->o_bd->be_modify( &o, &sreply );
    220      1.1     lukem 	o.o_bd->bd_info = (BackendInfo *)on;
    221  1.1.1.5  christos 	op->o_opid = opid;
    222  1.1.1.5  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    223      1.1     lukem 
    224      1.1     lukem 	return sreply.sr_err;
    225      1.1     lukem }
    226      1.1     lukem 
    227      1.1     lukem /*
    228      1.1     lukem ** dn,ndn	- the DN to be deleted
    229      1.1     lukem ** age		- the group from which the DN will be deleted
    230      1.1     lukem ** If we pass a NULL dn and ndn, all members are deleted from the group.
    231      1.1     lukem */
    232      1.1     lukem static int
    233      1.1     lukem autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
    234      1.1     lukem {
    235      1.1     lukem 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    236  1.1.1.4      tron 	Modifications	*modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
    237      1.1     lukem 	SlapReply	sreply = {REP_RESULT};
    238  1.1.1.4      tron 	BerValue	*vals, *nvals;
    239      1.1     lukem 	slap_callback	cb = { NULL, slap_null_cb, NULL, NULL };
    240      1.1     lukem 	Operation	o = *op;
    241  1.1.1.5  christos 	unsigned long opid = op->o_opid;
    242  1.1.1.5  christos 	OpExtra oex;
    243      1.1     lukem 
    244      1.1     lukem 	if ( dn == NULL || ndn == NULL ) {
    245      1.1     lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
    246      1.1     lukem 			age->age_dn.bv_val, 0 ,0);
    247      1.1     lukem 
    248  1.1.1.4      tron 		modlist->sml_values = NULL;
    249  1.1.1.4      tron 		modlist->sml_nvalues = NULL;
    250  1.1.1.4      tron 		modlist->sml_numvals = 0;
    251      1.1     lukem 	} else {
    252      1.1     lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
    253      1.1     lukem 			dn->bv_val, age->age_dn.bv_val, 0);
    254      1.1     lukem 
    255  1.1.1.4      tron 		vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    256  1.1.1.4      tron 		nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    257  1.1.1.4      tron 		ber_dupbv( vals, dn );
    258      1.1     lukem 		BER_BVZERO( &vals[ 1 ] );
    259  1.1.1.4      tron 		ber_dupbv( nvals, ndn );
    260      1.1     lukem 		BER_BVZERO( &nvals[ 1 ] );
    261      1.1     lukem 
    262  1.1.1.4      tron 		modlist->sml_values = vals;
    263  1.1.1.4      tron 		modlist->sml_nvalues = nvals;
    264  1.1.1.4      tron 		modlist->sml_numvals = 1;
    265      1.1     lukem 	}
    266      1.1     lukem 
    267      1.1     lukem 
    268  1.1.1.4      tron 	modlist->sml_op = LDAP_MOD_DELETE;
    269  1.1.1.4      tron 	modlist->sml_desc = age->age_def->agd_member_ad;
    270  1.1.1.4      tron 	modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
    271  1.1.1.4      tron 	modlist->sml_flags = SLAP_MOD_INTERNAL;
    272  1.1.1.4      tron 	modlist->sml_next = NULL;
    273      1.1     lukem 
    274  1.1.1.5  christos 	o.o_opid = 0;
    275      1.1     lukem 	o.o_callback = &cb;
    276      1.1     lukem 	o.o_tag = LDAP_REQ_MODIFY;
    277  1.1.1.4      tron 	o.orm_modlist = modlist;
    278  1.1.1.5  christos 	o.o_dn = op->o_bd->be_rootdn;
    279  1.1.1.5  christos 	o.o_ndn = op->o_bd->be_rootndn;
    280      1.1     lukem 	o.o_req_dn = age->age_dn;
    281      1.1     lukem 	o.o_req_ndn = age->age_ndn;
    282      1.1     lukem 	o.o_relax = SLAP_CONTROL_CRITICAL;
    283      1.1     lukem 	o.o_managedsait = SLAP_CONTROL_CRITICAL;
    284      1.1     lukem 	o.o_permissive_modify = 1;
    285  1.1.1.5  christos 	o.o_dont_replicate = 1;
    286  1.1.1.5  christos 	o.orm_no_opattrs = 1;
    287  1.1.1.5  christos 
    288  1.1.1.5  christos 	oex.oe_key = (void *)&autogroup;
    289  1.1.1.5  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    290      1.1     lukem 
    291      1.1     lukem 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    292      1.1     lukem 	(void)op->o_bd->be_modify( &o, &sreply );
    293      1.1     lukem 	o.o_bd->bd_info = (BackendInfo *)on;
    294      1.1     lukem 
    295  1.1.1.5  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    296  1.1.1.5  christos 
    297  1.1.1.4      tron 	slap_mods_free( modlist, 1 );
    298  1.1.1.4      tron 
    299  1.1.1.5  christos 	op->o_opid = opid;
    300      1.1     lukem 	return sreply.sr_err;
    301      1.1     lukem }
    302      1.1     lukem 
    303  1.1.1.4      tron /*
    304  1.1.1.4      tron **      e       - the entry where to get the attribute values
    305  1.1.1.4      tron **      age     - the group from which the values will be deleted
    306  1.1.1.4      tron */
    307  1.1.1.4      tron static int
    308  1.1.1.5  christos autogroup_delete_member_values_from_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
    309  1.1.1.4      tron {
    310  1.1.1.4      tron         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
    311  1.1.1.4      tron         Modifications   modlist;
    312  1.1.1.4      tron         SlapReply       sreply = {REP_RESULT};
    313  1.1.1.4      tron         slap_callback   cb = { NULL, slap_null_cb, NULL, NULL };
    314  1.1.1.4      tron         Operation       o = *op;
    315  1.1.1.5  christos 	unsigned long opid = op->o_opid;
    316  1.1.1.5  christos 	OpExtra oex;
    317  1.1.1.4      tron 
    318  1.1.1.4      tron         Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n",
    319  1.1.1.5  christos 			dn->bv_val, age->age_dn.bv_val, 0);
    320  1.1.1.4      tron 
    321  1.1.1.4      tron         modlist.sml_op = LDAP_MOD_DELETE;
    322  1.1.1.4      tron         modlist.sml_desc = age->age_def->agd_member_ad;
    323  1.1.1.4      tron         modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
    324  1.1.1.4      tron         modlist.sml_values = attr->a_vals;
    325  1.1.1.4      tron         modlist.sml_nvalues = attr->a_nvals;
    326  1.1.1.4      tron         modlist.sml_numvals = attr->a_numvals;
    327  1.1.1.4      tron         modlist.sml_flags = SLAP_MOD_INTERNAL;
    328  1.1.1.4      tron         modlist.sml_next = NULL;
    329  1.1.1.4      tron 
    330  1.1.1.5  christos 	o.o_opid = 0;
    331  1.1.1.4      tron         o.o_tag = LDAP_REQ_MODIFY;
    332  1.1.1.4      tron         o.o_callback = &cb;
    333  1.1.1.4      tron         o.orm_modlist = &modlist;
    334  1.1.1.5  christos 		o.o_dn = op->o_bd->be_rootdn;
    335  1.1.1.5  christos 		o.o_ndn = op->o_bd->be_rootndn;
    336  1.1.1.4      tron         o.o_req_dn = age->age_dn;
    337  1.1.1.4      tron         o.o_req_ndn = age->age_ndn;
    338  1.1.1.4      tron         o.o_permissive_modify = 1;
    339  1.1.1.5  christos 	o.o_dont_replicate = 1;
    340  1.1.1.5  christos 	o.orm_no_opattrs = 1;
    341  1.1.1.4      tron         o.o_managedsait = SLAP_CONTROL_CRITICAL;
    342  1.1.1.4      tron         o.o_relax = SLAP_CONTROL_CRITICAL;
    343  1.1.1.4      tron 
    344  1.1.1.5  christos 	oex.oe_key = (void *)&autogroup;
    345  1.1.1.5  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    346  1.1.1.5  christos 
    347  1.1.1.4      tron         o.o_bd->bd_info = (BackendInfo *)on->on_info;
    348  1.1.1.4      tron         (void)op->o_bd->be_modify( &o, &sreply );
    349  1.1.1.4      tron         o.o_bd->bd_info = (BackendInfo *)on;
    350  1.1.1.5  christos 	op->o_opid = opid;
    351  1.1.1.5  christos 
    352  1.1.1.5  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    353  1.1.1.4      tron 
    354  1.1.1.4      tron         return sreply.sr_err;
    355  1.1.1.4      tron }
    356  1.1.1.4      tron 
    357      1.1     lukem /*
    358      1.1     lukem ** Callback used to add entries to a group,
    359      1.1     lukem ** which are going to be written in the database
    360      1.1     lukem ** (used in bi_op_add)
    361      1.1     lukem ** The group is passed in autogroup_ga_t->agg_group
    362      1.1     lukem */
    363      1.1     lukem static int
    364      1.1     lukem autogroup_member_search_cb( Operation *op, SlapReply *rs )
    365      1.1     lukem {
    366      1.1     lukem 	assert( op->o_tag == LDAP_REQ_SEARCH );
    367      1.1     lukem 
    368      1.1     lukem 	if ( rs->sr_type == REP_SEARCH ) {
    369      1.1     lukem 		autogroup_ga_t		*agg = (autogroup_ga_t *)op->o_callback->sc_private;
    370      1.1     lukem 		autogroup_entry_t	*age = agg->agg_group;
    371  1.1.1.4      tron 		autogroup_filter_t	*agf = agg->agg_filter;
    372      1.1     lukem 		Modification		mod;
    373      1.1     lukem 		const char		*text = NULL;
    374      1.1     lukem 		char			textbuf[1024];
    375  1.1.1.4      tron 		struct berval		*vals, *nvals;
    376  1.1.1.4      tron 		struct berval		lvals[ 2 ], lnvals[ 2 ];
    377  1.1.1.4      tron 		int			numvals;
    378      1.1     lukem 
    379      1.1     lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
    380      1.1     lukem 			rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
    381      1.1     lukem 
    382  1.1.1.4      tron 		if ( agf->agf_anlist ) {
    383  1.1.1.4      tron 			Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
    384  1.1.1.4      tron 			if (attr) {
    385  1.1.1.4      tron 				vals = attr->a_vals;
    386  1.1.1.4      tron 				nvals = attr->a_nvals;
    387  1.1.1.4      tron 				numvals = attr->a_numvals;
    388  1.1.1.4      tron 			} else {
    389  1.1.1.4      tron 				// Nothing to add
    390  1.1.1.4      tron 				return 0;
    391  1.1.1.4      tron 			}
    392  1.1.1.4      tron 		} else {
    393  1.1.1.4      tron 			lvals[ 0 ] = rs->sr_entry->e_name;
    394  1.1.1.4      tron 			BER_BVZERO( &lvals[ 1 ] );
    395  1.1.1.4      tron 			lnvals[ 0 ] = rs->sr_entry->e_nname;
    396  1.1.1.4      tron 			BER_BVZERO( &lnvals[ 1 ] );
    397  1.1.1.4      tron 			vals = lvals;
    398  1.1.1.4      tron 			nvals = lnvals;
    399  1.1.1.4      tron 			numvals = 1;
    400  1.1.1.4      tron 		}
    401      1.1     lukem 
    402      1.1     lukem 		mod.sm_op = LDAP_MOD_ADD;
    403      1.1     lukem 		mod.sm_desc = age->age_def->agd_member_ad;
    404      1.1     lukem 		mod.sm_type = age->age_def->agd_member_ad->ad_cname;
    405      1.1     lukem 		mod.sm_values = vals;
    406      1.1     lukem 		mod.sm_nvalues = nvals;
    407  1.1.1.4      tron 		mod.sm_numvals = numvals;
    408      1.1     lukem 
    409      1.1     lukem 		modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
    410      1.1     lukem 	}
    411      1.1     lukem 
    412      1.1     lukem 	return 0;
    413      1.1     lukem }
    414      1.1     lukem 
    415      1.1     lukem /*
    416      1.1     lukem ** Callback used to add entries to a group, which is already in the database.
    417      1.1     lukem ** (used in on_response)
    418      1.1     lukem ** The group is passed in autogroup_ga_t->agg_group
    419      1.1     lukem ** NOTE: Very slow.
    420      1.1     lukem */
    421      1.1     lukem static int
    422      1.1     lukem autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
    423      1.1     lukem {
    424      1.1     lukem 	assert( op->o_tag == LDAP_REQ_SEARCH );
    425      1.1     lukem 
    426      1.1     lukem 	if ( rs->sr_type == REP_SEARCH ) {
    427      1.1     lukem 		autogroup_ga_t		*agg = (autogroup_ga_t *)op->o_callback->sc_private;
    428      1.1     lukem 		autogroup_entry_t	*age = agg->agg_group;
    429  1.1.1.4      tron 		autogroup_filter_t	*agf = agg->agg_filter;
    430      1.1     lukem 		Modifications		*modlist;
    431  1.1.1.4      tron 		struct berval		*vals, *nvals;
    432  1.1.1.4      tron 		struct berval		lvals[ 2 ], lnvals[ 2 ];
    433  1.1.1.4      tron 		int			numvals;
    434      1.1     lukem 
    435      1.1     lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
    436      1.1     lukem 			rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
    437      1.1     lukem 
    438  1.1.1.4      tron 		if ( agf->agf_anlist ) {
    439  1.1.1.4      tron 			Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
    440  1.1.1.4      tron 			if (attr) {
    441  1.1.1.4      tron 				vals = attr->a_vals;
    442  1.1.1.4      tron 				nvals = attr->a_nvals;
    443  1.1.1.4      tron 				numvals = attr->a_numvals;
    444  1.1.1.4      tron 			} else {
    445  1.1.1.4      tron 				// Nothing to add
    446  1.1.1.4      tron 				return 0;
    447  1.1.1.4      tron 			}
    448      1.1     lukem 		} else {
    449  1.1.1.4      tron 			lvals[ 0 ] = rs->sr_entry->e_name;
    450  1.1.1.4      tron 			BER_BVZERO( &lvals[ 1 ] );
    451  1.1.1.4      tron 			lnvals[ 0 ] = rs->sr_entry->e_nname;
    452  1.1.1.4      tron 			BER_BVZERO( &lnvals[ 1 ] );
    453  1.1.1.4      tron 			vals = lvals;
    454  1.1.1.4      tron 			nvals = lnvals;
    455  1.1.1.4      tron 			numvals = 1;
    456  1.1.1.4      tron 		}
    457  1.1.1.4      tron 
    458  1.1.1.4      tron 		if ( numvals ) {
    459  1.1.1.4      tron 			modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
    460  1.1.1.4      tron 
    461  1.1.1.4      tron 			modlist->sml_op = LDAP_MOD_ADD;
    462  1.1.1.4      tron 			modlist->sml_desc = age->age_def->agd_member_ad;
    463  1.1.1.4      tron 			modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
    464  1.1.1.4      tron 
    465  1.1.1.4      tron 			ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
    466  1.1.1.4      tron 			ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
    467  1.1.1.4      tron 			modlist->sml_numvals = numvals;
    468  1.1.1.4      tron 
    469  1.1.1.4      tron 			modlist->sml_flags = SLAP_MOD_INTERNAL;
    470  1.1.1.4      tron 			modlist->sml_next = NULL;
    471  1.1.1.4      tron 
    472  1.1.1.4      tron 			if ( agg->agg_mod == NULL ) {
    473  1.1.1.4      tron 				agg->agg_mod = modlist;
    474  1.1.1.4      tron 				agg->agg_mod_last = modlist;
    475  1.1.1.4      tron 			} else {
    476  1.1.1.4      tron 				agg->agg_mod_last->sml_next = modlist;
    477  1.1.1.4      tron 				agg->agg_mod_last = modlist;
    478  1.1.1.4      tron 			}
    479      1.1     lukem 		}
    480      1.1     lukem 
    481      1.1     lukem 	}
    482      1.1     lukem 
    483      1.1     lukem 	return 0;
    484      1.1     lukem }
    485      1.1     lukem 
    486      1.1     lukem 
    487      1.1     lukem /*
    488      1.1     lukem ** Adds all entries matching the passed filter to the specified group.
    489      1.1     lukem ** If modify == 1, then we modify the group's entry in the database using be_modify.
    490      1.1     lukem ** If modify == 0, then, we must supply a rw entry for the group,
    491      1.1     lukem **	because we only modify the entry, without calling be_modify.
    492      1.1     lukem ** e	- the group entry, to which the members will be added
    493      1.1     lukem ** age	- the group
    494      1.1     lukem ** agf	- the filter
    495      1.1     lukem */
    496      1.1     lukem static int
    497      1.1     lukem autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
    498      1.1     lukem {
    499      1.1     lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    500      1.1     lukem 	Operation		o = *op;
    501      1.1     lukem 	SlapReply		rs = { REP_SEARCH };
    502      1.1     lukem 	slap_callback		cb = { 0 };
    503      1.1     lukem 	slap_callback		null_cb = { NULL, slap_null_cb, NULL, NULL };
    504      1.1     lukem 	autogroup_ga_t		agg;
    505  1.1.1.5  christos 	OpExtra oex;
    506      1.1     lukem 
    507      1.1     lukem 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
    508      1.1     lukem 		age->age_dn.bv_val, 0, 0);
    509      1.1     lukem 
    510      1.1     lukem 	o.ors_attrsonly = 0;
    511      1.1     lukem 	o.o_tag = LDAP_REQ_SEARCH;
    512      1.1     lukem 
    513  1.1.1.5  christos 	o.o_dn = op->o_bd->be_rootdn;
    514  1.1.1.5  christos 	o.o_ndn = op->o_bd->be_rootndn;
    515      1.1     lukem 	o.o_req_dn = agf->agf_dn;
    516      1.1     lukem 	o.o_req_ndn = agf->agf_ndn;
    517      1.1     lukem 
    518      1.1     lukem 	o.ors_filterstr = agf->agf_filterstr;
    519      1.1     lukem 	o.ors_filter = agf->agf_filter;
    520      1.1     lukem 
    521      1.1     lukem 	o.ors_scope = agf->agf_scope;
    522      1.1     lukem 	o.ors_deref = LDAP_DEREF_NEVER;
    523      1.1     lukem 	o.ors_limit = NULL;
    524      1.1     lukem 	o.ors_tlimit = SLAP_NO_LIMIT;
    525      1.1     lukem 	o.ors_slimit = SLAP_NO_LIMIT;
    526  1.1.1.4      tron 	o.ors_attrs =  agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
    527  1.1.1.5  christos 	o.o_do_not_cache = 1;
    528      1.1     lukem 
    529      1.1     lukem 	agg.agg_group = age;
    530  1.1.1.4      tron 	agg.agg_filter = agf;
    531      1.1     lukem 	agg.agg_mod = NULL;
    532      1.1     lukem 	agg.agg_mod_last = NULL;
    533      1.1     lukem 	agg.agg_entry = e;
    534      1.1     lukem 	cb.sc_private = &agg;
    535      1.1     lukem 
    536      1.1     lukem 	if ( modify == 1 ) {
    537      1.1     lukem 		cb.sc_response = autogroup_member_search_modify_cb;
    538      1.1     lukem 	} else {
    539      1.1     lukem 		cb.sc_response = autogroup_member_search_cb;
    540      1.1     lukem 	}
    541      1.1     lukem 
    542      1.1     lukem 	cb.sc_cleanup = NULL;
    543      1.1     lukem 	cb.sc_next = NULL;
    544      1.1     lukem 
    545      1.1     lukem 	o.o_callback = &cb;
    546      1.1     lukem 
    547      1.1     lukem 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    548      1.1     lukem 	op->o_bd->be_search( &o, &rs );
    549      1.1     lukem 	o.o_bd->bd_info = (BackendInfo *)on;
    550      1.1     lukem 
    551  1.1.1.4      tron 	if ( modify == 1 && agg.agg_mod ) {
    552  1.1.1.5  christos 		unsigned long opid = op->o_opid;
    553  1.1.1.5  christos 
    554  1.1.1.4      tron 		rs_reinit( &rs, REP_RESULT );
    555  1.1.1.4      tron 
    556      1.1     lukem 		o = *op;
    557  1.1.1.5  christos 		o.o_opid = 0;
    558      1.1     lukem 		o.o_callback = &null_cb;
    559      1.1     lukem 		o.o_tag = LDAP_REQ_MODIFY;
    560      1.1     lukem 		o.orm_modlist = agg.agg_mod;
    561  1.1.1.5  christos 		o.o_dn = op->o_bd->be_rootdn;
    562  1.1.1.5  christos 		o.o_ndn = op->o_bd->be_rootndn;
    563      1.1     lukem 		o.o_req_dn = age->age_dn;
    564      1.1     lukem 		o.o_req_ndn = age->age_ndn;
    565      1.1     lukem 		o.o_relax = SLAP_CONTROL_CRITICAL;
    566      1.1     lukem 		o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
    567      1.1     lukem 		o.o_permissive_modify = 1;
    568  1.1.1.5  christos 		o.o_dont_replicate = 1;
    569  1.1.1.5  christos 		o.orm_no_opattrs = 1;
    570  1.1.1.5  christos 
    571  1.1.1.5  christos 	oex.oe_key = (void *)&autogroup;
    572  1.1.1.5  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    573      1.1     lukem 
    574      1.1     lukem 		o.o_bd->bd_info = (BackendInfo *)on->on_info;
    575      1.1     lukem 		(void)op->o_bd->be_modify( &o, &rs );
    576      1.1     lukem 		o.o_bd->bd_info = (BackendInfo *)on;
    577      1.1     lukem 
    578  1.1.1.5  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    579  1.1.1.5  christos 
    580      1.1     lukem 		slap_mods_free(agg.agg_mod, 1);
    581  1.1.1.5  christos 		op->o_opid = opid;
    582      1.1     lukem 	}
    583      1.1     lukem 
    584      1.1     lukem 	return 0;
    585      1.1     lukem }
    586      1.1     lukem 
    587      1.1     lukem /*
    588      1.1     lukem ** Adds a group to the internal list from the passed entry.
    589      1.1     lukem ** scan specifies whether to add all maching members to the group.
    590      1.1     lukem ** modify specifies whether to modify the given group entry (when modify == 0),
    591      1.1     lukem **	or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
    592      1.1     lukem ** agi	- pointer to the groups and the attribute definitions
    593      1.1     lukem ** agd - the attribute definition of the added group
    594      1.1     lukem ** e	- the entry representing the group, can be NULL if the ndn is specified, and modify == 1
    595      1.1     lukem ** ndn	- the DN of the group, can be NULL if we give a non-NULL e
    596      1.1     lukem */
    597      1.1     lukem static int
    598      1.1     lukem autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
    599      1.1     lukem {
    600      1.1     lukem 	autogroup_entry_t	**agep = &agi->agi_entry;
    601      1.1     lukem 	autogroup_filter_t	*agf, *agf_prev = NULL;
    602      1.1     lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    603      1.1     lukem 	LDAPURLDesc		*lud = NULL;
    604      1.1     lukem 	Attribute		*a;
    605      1.1     lukem 	BerValue		*bv, dn;
    606      1.1     lukem 	int			rc = 0, match = 1, null_entry = 0;
    607      1.1     lukem 
    608      1.1     lukem 	if ( e == NULL ) {
    609      1.1     lukem 		if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
    610      1.1     lukem 			LDAP_SUCCESS || e == NULL ) {
    611      1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
    612      1.1     lukem 			return 1;
    613      1.1     lukem 		}
    614      1.1     lukem 
    615      1.1     lukem 		null_entry = 1;
    616      1.1     lukem 	}
    617      1.1     lukem 
    618      1.1     lukem 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
    619      1.1     lukem 		e->e_name.bv_val, 0, 0);
    620      1.1     lukem 
    621      1.1     lukem 	if ( agi->agi_entry != NULL ) {
    622      1.1     lukem 		for ( ; *agep ; agep = &(*agep)->age_next ) {
    623      1.1     lukem 			dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
    624      1.1     lukem 			if ( match == 0 ) {
    625      1.1     lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
    626      1.1     lukem 				return 1;
    627      1.1     lukem 			}
    628      1.1     lukem 			/* goto last */;
    629      1.1     lukem 		}
    630      1.1     lukem 	}
    631      1.1     lukem 
    632      1.1     lukem 
    633      1.1     lukem 	*agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
    634      1.1     lukem 	ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
    635      1.1     lukem 	(*agep)->age_def = agd;
    636      1.1     lukem 	(*agep)->age_filter = NULL;
    637  1.1.1.4      tron 	(*agep)->age_mustrefresh = 0;
    638  1.1.1.4      tron 	(*agep)->age_modrdn_olddnmodified = 0;
    639      1.1     lukem 
    640      1.1     lukem 	ber_dupbv( &(*agep)->age_dn, &e->e_name );
    641      1.1     lukem 	ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
    642      1.1     lukem 
    643      1.1     lukem 	a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
    644      1.1     lukem 
    645      1.1     lukem 	if ( null_entry == 1 ) {
    646      1.1     lukem 		a = attrs_dup( a );
    647      1.1     lukem 		overlay_entry_release_ov( op, e, 0, on );
    648      1.1     lukem 	}
    649      1.1     lukem 
    650      1.1     lukem 	if( a == NULL ) {
    651      1.1     lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
    652      1.1     lukem 	} else {
    653      1.1     lukem 		for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
    654      1.1     lukem 
    655      1.1     lukem 			agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
    656      1.1     lukem 
    657      1.1     lukem 			if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
    658      1.1     lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
    659      1.1     lukem 				/* FIXME: error? */
    660      1.1     lukem 				ch_free( agf );
    661      1.1     lukem 				continue;
    662      1.1     lukem 			}
    663      1.1     lukem 
    664      1.1     lukem 			agf->agf_scope = lud->lud_scope;
    665      1.1     lukem 
    666      1.1     lukem 			if ( lud->lud_dn == NULL ) {
    667      1.1     lukem 				BER_BVSTR( &dn, "" );
    668      1.1     lukem 			} else {
    669      1.1     lukem 				ber_str2bv( lud->lud_dn, 0, 0, &dn );
    670      1.1     lukem 			}
    671      1.1     lukem 
    672      1.1     lukem 			rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
    673      1.1     lukem 			if ( rc != LDAP_SUCCESS ) {
    674      1.1     lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
    675      1.1     lukem 				/* FIXME: error? */
    676      1.1     lukem 				goto cleanup;
    677      1.1     lukem 			}
    678      1.1     lukem 
    679      1.1     lukem 			if ( lud->lud_filter != NULL ) {
    680      1.1     lukem 				ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
    681      1.1     lukem 				agf->agf_filter = str2filter( lud->lud_filter );
    682  1.1.1.5  christos 			} else {
    683  1.1.1.5  christos 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: URL filter is missing <%s>\n", bv->bv_val,0,0);
    684  1.1.1.5  christos 				/* FIXME: error? */
    685  1.1.1.5  christos 				goto cleanup;
    686  1.1.1.5  christos 			}
    687      1.1     lukem 
    688  1.1.1.4      tron 			if ( lud->lud_attrs != NULL ) {
    689  1.1.1.4      tron 				int i;
    690  1.1.1.4      tron 
    691  1.1.1.4      tron 				for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
    692  1.1.1.4      tron 					/* Just counting */;
    693  1.1.1.4      tron 				}
    694  1.1.1.4      tron 
    695  1.1.1.4      tron 				if ( i > 1 ) {
    696  1.1.1.4      tron 					Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n",
    697  1.1.1.4      tron 						bv->bv_val, 0, 0);
    698  1.1.1.4      tron 					/* FIXME: error? */
    699  1.1.1.5  christos 					filter_free( agf->agf_filter );
    700  1.1.1.5  christos 					ch_free( agf->agf_filterstr.bv_val );
    701  1.1.1.5  christos 					ch_free( agf->agf_dn.bv_val );
    702  1.1.1.5  christos 					ch_free( agf->agf_ndn.bv_val );
    703  1.1.1.4      tron 					ldap_free_urldesc( lud );
    704  1.1.1.5  christos 					ch_free( agf );
    705  1.1.1.4      tron 					continue;
    706  1.1.1.4      tron 				}
    707  1.1.1.5  christos 
    708  1.1.1.4      tron 				agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
    709  1.1.1.4      tron 
    710  1.1.1.4      tron 				if ( agf->agf_anlist == NULL ) {
    711  1.1.1.4      tron 					Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
    712  1.1.1.5  christos 						lud->lud_attrs[0], 0, 0 );
    713  1.1.1.4      tron 					/* FIXME: error? */
    714  1.1.1.5  christos 					filter_free( agf->agf_filter );
    715  1.1.1.5  christos 					ch_free( agf->agf_filterstr.bv_val );
    716  1.1.1.5  christos 					ch_free( agf->agf_dn.bv_val );
    717  1.1.1.5  christos 					ch_free( agf->agf_ndn.bv_val );
    718  1.1.1.4      tron 					ldap_free_urldesc( lud );
    719  1.1.1.5  christos 					ch_free( agf );
    720  1.1.1.4      tron 					continue;
    721  1.1.1.4      tron 				}
    722  1.1.1.4      tron 			}
    723  1.1.1.4      tron 
    724      1.1     lukem 			agf->agf_next = NULL;
    725      1.1     lukem 
    726      1.1     lukem 			if( (*agep)->age_filter == NULL ) {
    727      1.1     lukem 				(*agep)->age_filter = agf;
    728      1.1     lukem 			}
    729      1.1     lukem 
    730      1.1     lukem 			if( agf_prev != NULL ) {
    731      1.1     lukem 				agf_prev->agf_next = agf;
    732      1.1     lukem 			}
    733      1.1     lukem 
    734      1.1     lukem 			agf_prev = agf;
    735      1.1     lukem 
    736      1.1     lukem 			if ( scan == 1 ){
    737      1.1     lukem 				autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
    738      1.1     lukem 			}
    739      1.1     lukem 
    740      1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
    741      1.1     lukem 				agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
    742      1.1     lukem 
    743      1.1     lukem 			ldap_free_urldesc( lud );
    744      1.1     lukem 
    745      1.1     lukem 			continue;
    746      1.1     lukem 
    747      1.1     lukem 
    748      1.1     lukem cleanup:;
    749      1.1     lukem 
    750  1.1.1.5  christos 			ch_free( agf->agf_ndn.bv_val );
    751  1.1.1.5  christos 			ch_free( agf->agf_dn.bv_val );
    752      1.1     lukem 			ldap_free_urldesc( lud );
    753      1.1     lukem 			ch_free( agf );
    754      1.1     lukem 		}
    755      1.1     lukem 	}
    756      1.1     lukem 
    757      1.1     lukem 	if ( null_entry == 1 ) {
    758      1.1     lukem 		attrs_free( a );
    759      1.1     lukem 	}
    760      1.1     lukem 	return rc;
    761      1.1     lukem }
    762      1.1     lukem 
    763      1.1     lukem /*
    764      1.1     lukem ** Used when opening the database to add all existing
    765      1.1     lukem ** groups from the database to our internal list.
    766      1.1     lukem */
    767      1.1     lukem static int
    768      1.1     lukem autogroup_group_add_cb( Operation *op, SlapReply *rs )
    769      1.1     lukem {
    770      1.1     lukem 	assert( op->o_tag == LDAP_REQ_SEARCH );
    771      1.1     lukem 
    772      1.1     lukem 	if ( rs->sr_type == REP_SEARCH ) {
    773      1.1     lukem 		autogroup_sc_t		*ags = (autogroup_sc_t *)op->o_callback->sc_private;
    774      1.1     lukem 
    775      1.1     lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
    776      1.1     lukem 			rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
    777      1.1     lukem 
    778      1.1     lukem 		autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
    779      1.1     lukem 	}
    780      1.1     lukem 
    781      1.1     lukem 	return 0;
    782      1.1     lukem }
    783      1.1     lukem 
    784  1.1.1.5  christos typedef struct ag_addinfo {
    785  1.1.1.5  christos 	slap_overinst *on;
    786  1.1.1.5  christos 	Entry *e;
    787  1.1.1.5  christos 	autogroup_def_t		*agd;
    788  1.1.1.5  christos } ag_addinfo;
    789  1.1.1.5  christos 
    790  1.1.1.5  christos static int
    791  1.1.1.5  christos autogroup_add_entry_cb( Operation *op, SlapReply *rs )
    792  1.1.1.5  christos {
    793  1.1.1.5  christos 	slap_callback *sc = op->o_callback;
    794  1.1.1.5  christos 	ag_addinfo *aa = sc->sc_private;
    795  1.1.1.5  christos 	slap_overinst *on = aa->on;
    796  1.1.1.5  christos 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
    797  1.1.1.5  christos 	BackendInfo *bi = op->o_bd->bd_info;
    798  1.1.1.5  christos 
    799  1.1.1.5  christos 	if ( rs->sr_err != LDAP_SUCCESS )
    800  1.1.1.5  christos 		goto done;
    801  1.1.1.5  christos 
    802  1.1.1.5  christos 	op->o_bd->bd_info = (BackendInfo *)on;
    803  1.1.1.5  christos 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
    804  1.1.1.5  christos 	if ( aa->agd ) {
    805  1.1.1.5  christos 		autogroup_add_group( op, agi, aa->agd, aa->e, NULL, 1 , 0);
    806  1.1.1.5  christos 	} else {
    807  1.1.1.5  christos 		autogroup_entry_t	*age;
    808  1.1.1.5  christos 		autogroup_filter_t	*agf;
    809  1.1.1.5  christos 		struct berval odn, ondn;
    810  1.1.1.5  christos 		int rc;
    811  1.1.1.5  christos 
    812  1.1.1.5  christos 		/* must use rootdn when calling test_filter */
    813  1.1.1.5  christos 		odn = op->o_dn;
    814  1.1.1.5  christos 		ondn = op->o_ndn;
    815  1.1.1.5  christos 		op->o_dn = op->o_bd->be_rootdn;
    816  1.1.1.5  christos 		op->o_ndn = op->o_bd->be_rootndn;
    817  1.1.1.5  christos 
    818  1.1.1.5  christos 		for ( age = agi->agi_entry; age ; age = age->age_next ) {
    819  1.1.1.5  christos 			ldap_pvt_thread_mutex_lock( &age->age_mutex );
    820  1.1.1.5  christos 
    821  1.1.1.5  christos 			/* Check if any of the filters are the suffix to the entry DN.
    822  1.1.1.5  christos 			   If yes, we can test that filter against the entry. */
    823  1.1.1.5  christos 
    824  1.1.1.5  christos 			for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
    825  1.1.1.5  christos 				if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
    826  1.1.1.5  christos 					rc = test_filter( op, aa->e, agf->agf_filter );
    827  1.1.1.5  christos 					if ( rc == LDAP_COMPARE_TRUE ) {
    828  1.1.1.5  christos 						if ( agf->agf_anlist ) {
    829  1.1.1.5  christos 							Attribute *a = attr_find( aa->e->e_attrs, agf->agf_anlist[0].an_desc );
    830  1.1.1.5  christos 							if ( a )
    831  1.1.1.5  christos 								autogroup_add_member_values_to_group( op, &op->o_req_dn, age, a );
    832  1.1.1.5  christos 						} else {
    833  1.1.1.5  christos 							autogroup_add_member_to_group( op, &aa->e->e_name, &aa->e->e_nname, age );
    834  1.1.1.5  christos 						}
    835  1.1.1.5  christos 						break;
    836  1.1.1.5  christos 					}
    837  1.1.1.5  christos 				}
    838  1.1.1.5  christos 			}
    839  1.1.1.5  christos 			ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    840  1.1.1.5  christos 		}
    841  1.1.1.5  christos 		op->o_dn = odn;
    842  1.1.1.5  christos 		op->o_ndn = ondn;
    843  1.1.1.5  christos 	}
    844  1.1.1.5  christos 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    845  1.1.1.5  christos 
    846  1.1.1.5  christos 	op->o_bd->bd_info = bi;
    847  1.1.1.5  christos 
    848  1.1.1.5  christos done:
    849  1.1.1.5  christos 	op->o_callback = sc->sc_next;
    850  1.1.1.5  christos 	op->o_tmpfree( sc, op->o_tmpmemctx );
    851  1.1.1.5  christos 
    852  1.1.1.5  christos 	return SLAP_CB_CONTINUE;
    853  1.1.1.5  christos }
    854      1.1     lukem 
    855      1.1     lukem /*
    856      1.1     lukem ** When adding a group, we first strip any existing members,
    857      1.1     lukem ** and add all which match the filters ourselfs.
    858      1.1     lukem */
    859      1.1     lukem static int
    860      1.1     lukem autogroup_add_entry( Operation *op, SlapReply *rs)
    861      1.1     lukem {
    862  1.1.1.4      tron 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    863  1.1.1.4      tron 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
    864      1.1     lukem 	autogroup_def_t		*agd = agi->agi_def;
    865  1.1.1.5  christos 	slap_callback	*sc = NULL;
    866  1.1.1.5  christos 	ag_addinfo	*aa = NULL;
    867      1.1     lukem 
    868      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
    869      1.1     lukem 		op->ora_e->e_name.bv_val, 0, 0);
    870      1.1     lukem 
    871  1.1.1.5  christos 	sc = op->o_tmpcalloc( sizeof(slap_callback) + sizeof(ag_addinfo), 1, op->o_tmpmemctx );
    872  1.1.1.5  christos 	sc->sc_private = (sc+1);
    873  1.1.1.5  christos 	sc->sc_response = autogroup_add_entry_cb;
    874  1.1.1.5  christos 	aa = sc->sc_private;
    875  1.1.1.5  christos 	aa->on = on;
    876  1.1.1.5  christos 	aa->e = op->ora_e;
    877  1.1.1.5  christos 	sc->sc_next = op->o_callback;
    878  1.1.1.5  christos 	op->o_callback = sc;
    879      1.1     lukem 
    880      1.1     lukem 	/* Check if it's a group. */
    881      1.1     lukem 	for ( ; agd ; agd = agd->agd_next ) {
    882      1.1     lukem 		if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
    883      1.1     lukem 			Modification		mod;
    884      1.1     lukem 			const char		*text = NULL;
    885      1.1     lukem 			char			textbuf[1024];
    886      1.1     lukem 
    887      1.1     lukem 			mod.sm_op = LDAP_MOD_DELETE;
    888      1.1     lukem 			mod.sm_desc = agd->agd_member_ad;
    889      1.1     lukem 			mod.sm_type = agd->agd_member_ad->ad_cname;
    890      1.1     lukem 			mod.sm_values = NULL;
    891      1.1     lukem 			mod.sm_nvalues = NULL;
    892      1.1     lukem 
    893      1.1     lukem 			/* We don't want any member attributes added by the user. */
    894      1.1     lukem 			modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
    895      1.1     lukem 
    896  1.1.1.5  christos 			aa->agd = agd;
    897      1.1     lukem 
    898  1.1.1.5  christos 			break;
    899      1.1     lukem 		}
    900      1.1     lukem 	}
    901      1.1     lukem 
    902      1.1     lukem 	return SLAP_CB_CONTINUE;
    903      1.1     lukem }
    904      1.1     lukem 
    905      1.1     lukem /*
    906      1.1     lukem ** agi	- internal group and attribute definitions list
    907      1.1     lukem ** e	- the group to remove from the internal list
    908      1.1     lukem */
    909      1.1     lukem static int
    910      1.1     lukem autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
    911      1.1     lukem {
    912      1.1     lukem 	autogroup_entry_t	*age = agi->agi_entry,
    913      1.1     lukem 				*age_prev = NULL,
    914      1.1     lukem 				*age_next;
    915      1.1     lukem 	int			rc = 1;
    916      1.1     lukem 
    917      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
    918      1.1     lukem 		age->age_dn.bv_val, 0, 0);
    919      1.1     lukem 
    920      1.1     lukem 	for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
    921      1.1     lukem 		age_next = age->age_next;
    922      1.1     lukem 
    923      1.1     lukem 		if ( age == e ) {
    924      1.1     lukem 			autogroup_filter_t	*agf = age->age_filter,
    925      1.1     lukem 							*agf_next;
    926      1.1     lukem 
    927      1.1     lukem 			if ( age_prev != NULL ) {
    928      1.1     lukem 				age_prev->age_next = age_next;
    929      1.1     lukem 			} else {
    930      1.1     lukem 				agi->agi_entry = NULL;
    931      1.1     lukem 			}
    932      1.1     lukem 
    933      1.1     lukem 			ch_free( age->age_dn.bv_val );
    934      1.1     lukem 			ch_free( age->age_ndn.bv_val );
    935      1.1     lukem 
    936      1.1     lukem 			for( agf_next = agf ; agf_next ; agf = agf_next ){
    937      1.1     lukem 				agf_next = agf->agf_next;
    938      1.1     lukem 
    939      1.1     lukem 				filter_free( agf->agf_filter );
    940      1.1     lukem 				ch_free( agf->agf_filterstr.bv_val );
    941      1.1     lukem 				ch_free( agf->agf_dn.bv_val );
    942      1.1     lukem 				ch_free( agf->agf_ndn.bv_val );
    943  1.1.1.4      tron 				anlist_free( agf->agf_anlist, 1, NULL );
    944  1.1.1.4      tron 				ch_free( agf );
    945      1.1     lukem 			}
    946      1.1     lukem 
    947      1.1     lukem 			ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    948      1.1     lukem 			ldap_pvt_thread_mutex_destroy( &age->age_mutex );
    949      1.1     lukem 			ch_free( age );
    950      1.1     lukem 
    951      1.1     lukem 			rc = 0;
    952      1.1     lukem 			return rc;
    953      1.1     lukem 
    954      1.1     lukem 		}
    955      1.1     lukem 	}
    956      1.1     lukem 
    957      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
    958      1.1     lukem 
    959      1.1     lukem 	return rc;
    960      1.1     lukem 
    961      1.1     lukem }
    962      1.1     lukem 
    963      1.1     lukem static int
    964      1.1     lukem autogroup_delete_entry( Operation *op, SlapReply *rs)
    965      1.1     lukem {
    966      1.1     lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    967  1.1.1.4      tron 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
    968  1.1.1.4      tron 	autogroup_entry_t	*age, *age_prev, *age_next;
    969      1.1     lukem 	autogroup_filter_t	*agf;
    970      1.1     lukem 	Entry			*e;
    971      1.1     lukem 	int			matched_group = 0, rc = 0;
    972  1.1.1.5  christos 	struct berval odn, ondn;
    973  1.1.1.5  christos 	OpExtra *oex;
    974  1.1.1.5  christos 
    975  1.1.1.5  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
    976  1.1.1.5  christos 		if ( oex->oe_key == (void *)&autogroup )
    977  1.1.1.5  christos 			return SLAP_CB_CONTINUE;
    978  1.1.1.5  christos 	}
    979      1.1     lukem 
    980      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
    981      1.1     lukem 
    982      1.1     lukem 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
    983      1.1     lukem 
    984      1.1     lukem 	if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
    985      1.1     lukem 		LDAP_SUCCESS || e == NULL ) {
    986      1.1     lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
    987      1.1     lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    988      1.1     lukem 		return SLAP_CB_CONTINUE;
    989      1.1     lukem 	}
    990      1.1     lukem 
    991      1.1     lukem 	/* Check if the entry to be deleted is one of our groups. */
    992  1.1.1.4      tron 	for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) {
    993  1.1.1.4      tron 		age = age_next;
    994      1.1     lukem 		ldap_pvt_thread_mutex_lock( &age->age_mutex );
    995      1.1     lukem 		age_next = age->age_next;
    996      1.1     lukem 
    997      1.1     lukem 		if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
    998      1.1     lukem 			int match = 1;
    999      1.1     lukem 
   1000      1.1     lukem 			matched_group = 1;
   1001      1.1     lukem 
   1002      1.1     lukem 			dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
   1003      1.1     lukem 
   1004      1.1     lukem 			if ( match == 0 ) {
   1005      1.1     lukem 				autogroup_delete_group( agi, age );
   1006      1.1     lukem 				break;
   1007      1.1     lukem 			}
   1008      1.1     lukem 		}
   1009      1.1     lukem 
   1010      1.1     lukem 		ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1011      1.1     lukem 	}
   1012      1.1     lukem 
   1013      1.1     lukem 	if ( matched_group == 1 ) {
   1014      1.1     lukem 		overlay_entry_release_ov( op, e, 0, on );
   1015      1.1     lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1016      1.1     lukem 		return SLAP_CB_CONTINUE;
   1017      1.1     lukem 	}
   1018      1.1     lukem 
   1019      1.1     lukem 	/* Check if the entry matches any of the groups.
   1020      1.1     lukem 	   If yes, we can delete the entry from that group. */
   1021      1.1     lukem 
   1022  1.1.1.5  christos 	odn = op->o_dn;
   1023  1.1.1.5  christos 	ondn = op->o_ndn;
   1024  1.1.1.5  christos 	op->o_dn = op->o_bd->be_rootdn;
   1025  1.1.1.5  christos 	op->o_ndn = op->o_bd->be_rootndn;
   1026  1.1.1.5  christos 
   1027      1.1     lukem 	for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1028      1.1     lukem 		ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1029      1.1     lukem 
   1030      1.1     lukem 		for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
   1031      1.1     lukem 			if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
   1032      1.1     lukem 				rc = test_filter( op, e, agf->agf_filter );
   1033      1.1     lukem 				if ( rc == LDAP_COMPARE_TRUE ) {
   1034  1.1.1.4      tron 					/* If the attribute is retrieved from the entry, we don't know what to delete
   1035  1.1.1.4      tron 					** So the group must be entirely refreshed
   1036  1.1.1.4      tron 					** But the refresh can't be done now because the entry is not deleted
   1037  1.1.1.4      tron 					** So the group is marked as mustrefresh
   1038  1.1.1.4      tron 					*/
   1039  1.1.1.4      tron 					if ( agf->agf_anlist ) {
   1040  1.1.1.4      tron 						age->age_mustrefresh = 1;
   1041  1.1.1.4      tron 					} else {
   1042  1.1.1.4      tron 						autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
   1043  1.1.1.4      tron 					}
   1044      1.1     lukem 					break;
   1045      1.1     lukem 				}
   1046      1.1     lukem 			}
   1047      1.1     lukem 		}
   1048      1.1     lukem 		ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1049      1.1     lukem 	}
   1050  1.1.1.5  christos 	op->o_dn = odn;
   1051  1.1.1.5  christos 	op->o_ndn = ondn;
   1052      1.1     lukem 
   1053      1.1     lukem 	overlay_entry_release_ov( op, e, 0, on );
   1054      1.1     lukem 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1055      1.1     lukem 
   1056      1.1     lukem 	return SLAP_CB_CONTINUE;
   1057      1.1     lukem }
   1058      1.1     lukem 
   1059      1.1     lukem static int
   1060      1.1     lukem autogroup_response( Operation *op, SlapReply *rs )
   1061      1.1     lukem {
   1062      1.1     lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
   1063  1.1.1.4      tron 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
   1064      1.1     lukem 	autogroup_def_t		*agd = agi->agi_def;
   1065  1.1.1.4      tron 	autogroup_entry_t	*age;
   1066      1.1     lukem 	autogroup_filter_t	*agf;
   1067      1.1     lukem 	BerValue		new_dn, new_ndn, pdn;
   1068      1.1     lukem 	Entry			*e, *group;
   1069  1.1.1.5  christos 	Attribute		*a, *ea, *attrs;
   1070  1.1.1.4      tron 	int			is_olddn, is_newdn, is_value_refresh, dn_equal;
   1071  1.1.1.5  christos 	OpExtra *oex;
   1072  1.1.1.5  christos 
   1073  1.1.1.5  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
   1074  1.1.1.5  christos 		if ( oex->oe_key == (void *)&autogroup )
   1075  1.1.1.5  christos 			break;
   1076  1.1.1.5  christos 	}
   1077      1.1     lukem 
   1078  1.1.1.4      tron 	/* Handle all cases where a refresh of the group is needed */
   1079  1.1.1.4      tron 	if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
   1080  1.1.1.5  christos 		if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
   1081  1.1.1.4      tron 
   1082  1.1.1.4      tron 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1083  1.1.1.4      tron 
   1084  1.1.1.4      tron 			for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1085  1.1.1.4      tron 				/* Request detected that the group must be refreshed */
   1086  1.1.1.4      tron 
   1087  1.1.1.4      tron 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1088  1.1.1.4      tron 
   1089  1.1.1.4      tron 				if ( age->age_mustrefresh ) {
   1090  1.1.1.4      tron 					autogroup_delete_member_from_group( op, NULL, NULL, age) ;
   1091  1.1.1.4      tron 
   1092  1.1.1.4      tron 					for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1093  1.1.1.4      tron 						autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
   1094  1.1.1.4      tron 					}
   1095  1.1.1.4      tron 				}
   1096  1.1.1.4      tron 
   1097  1.1.1.4      tron 				ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1098  1.1.1.4      tron 			}
   1099  1.1.1.4      tron 
   1100  1.1.1.4      tron 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1101  1.1.1.4      tron 		}
   1102  1.1.1.4      tron 	} else if ( op->o_tag == LDAP_REQ_MODRDN ) {
   1103  1.1.1.5  christos 		if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
   1104      1.1     lukem 
   1105      1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1106      1.1     lukem 
   1107      1.1     lukem 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1108      1.1     lukem 
   1109      1.1     lukem 			if ( op->oq_modrdn.rs_newSup ) {
   1110      1.1     lukem 				pdn = *op->oq_modrdn.rs_newSup;
   1111      1.1     lukem 			} else {
   1112      1.1     lukem 				dnParent( &op->o_req_dn, &pdn );
   1113      1.1     lukem 			}
   1114      1.1     lukem 			build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
   1115      1.1     lukem 
   1116      1.1     lukem 			if ( op->oq_modrdn.rs_nnewSup ) {
   1117      1.1     lukem 				pdn = *op->oq_modrdn.rs_nnewSup;
   1118      1.1     lukem 			} else {
   1119      1.1     lukem 				dnParent( &op->o_req_ndn, &pdn );
   1120      1.1     lukem 			}
   1121      1.1     lukem 			build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
   1122      1.1     lukem 
   1123      1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
   1124      1.1     lukem 
   1125      1.1     lukem 			dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
   1126      1.1     lukem 
   1127      1.1     lukem 			if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
   1128      1.1     lukem 				LDAP_SUCCESS || e == NULL ) {
   1129      1.1     lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
   1130      1.1     lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1131      1.1     lukem 				return SLAP_CB_CONTINUE;
   1132      1.1     lukem 			}
   1133      1.1     lukem 
   1134      1.1     lukem 			a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
   1135      1.1     lukem 
   1136      1.1     lukem 
   1137      1.1     lukem 			if ( a == NULL ) {
   1138      1.1     lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
   1139      1.1     lukem 				overlay_entry_release_ov( op, e, 0, on );
   1140      1.1     lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1141      1.1     lukem 				return SLAP_CB_CONTINUE;
   1142      1.1     lukem 			}
   1143      1.1     lukem 
   1144      1.1     lukem 
   1145      1.1     lukem 			/* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
   1146      1.1     lukem 			for ( ; agd; agd = agd->agd_next ) {
   1147      1.1     lukem 
   1148      1.1     lukem 				if ( value_find_ex( slap_schema.si_ad_objectClass,
   1149      1.1     lukem 						SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   1150      1.1     lukem 						SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
   1151      1.1     lukem 						a->a_nvals, &agd->agd_oc->soc_cname,
   1152      1.1     lukem 						op->o_tmpmemctx ) == 0 )
   1153      1.1     lukem 				{
   1154      1.1     lukem 					for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1155      1.1     lukem 						int match = 1;
   1156      1.1     lukem 
   1157      1.1     lukem 						dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
   1158      1.1     lukem 						if ( match == 0 ) {
   1159      1.1     lukem 							Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
   1160      1.1     lukem 							ber_dupbv( &age->age_dn, &new_dn );
   1161      1.1     lukem 							ber_dupbv( &age->age_ndn, &new_ndn );
   1162      1.1     lukem 
   1163      1.1     lukem 							op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx  );
   1164      1.1     lukem 							op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
   1165      1.1     lukem 							overlay_entry_release_ov( op, e, 0, on );
   1166      1.1     lukem 							ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1167      1.1     lukem 							return SLAP_CB_CONTINUE;
   1168      1.1     lukem 						}
   1169      1.1     lukem 					}
   1170      1.1     lukem 
   1171      1.1     lukem 				}
   1172      1.1     lukem 			}
   1173      1.1     lukem 
   1174      1.1     lukem 			/* For each group:
   1175      1.1     lukem 			   1. check if the orginal entry's DN is in the group.
   1176      1.1     lukem 			   2. chceck if the any of the group filter's base DN is a suffix of the new DN
   1177      1.1     lukem 
   1178      1.1     lukem 			   If 1 and 2 are both false, we do nothing.
   1179      1.1     lukem 			   If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
   1180      1.1     lukem 			   If 1 is false, and 2 is true, we check the entry against the group's filters,
   1181      1.1     lukem 				and add it's DN to the group.
   1182      1.1     lukem 			   If 1 is true, and 2 is false, we delete the entry's DN from the group.
   1183      1.1     lukem 			*/
   1184  1.1.1.5  christos 			attrs = attrs_dup( e->e_attrs );
   1185  1.1.1.5  christos 			overlay_entry_release_ov( op, e, 0, on );
   1186      1.1     lukem 			for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1187      1.1     lukem 				is_olddn = 0;
   1188      1.1     lukem 				is_newdn = 0;
   1189  1.1.1.4      tron 				is_value_refresh = 0;
   1190      1.1     lukem 
   1191      1.1     lukem 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1192      1.1     lukem 
   1193  1.1.1.4      tron 				if ( age->age_filter && age->age_filter->agf_anlist ) {
   1194  1.1.1.5  christos 					ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
   1195  1.1.1.4      tron 				}
   1196  1.1.1.4      tron 				else {
   1197  1.1.1.4      tron 					ea = NULL;
   1198  1.1.1.4      tron 				}
   1199      1.1     lukem 
   1200  1.1.1.4      tron 				if ( age->age_modrdn_olddnmodified ) {
   1201  1.1.1.4      tron 					/* Resquest already marked this group to be updated */
   1202  1.1.1.4      tron 					is_olddn = 1;
   1203  1.1.1.4      tron 					is_value_refresh = 1;
   1204  1.1.1.4      tron 					age->age_modrdn_olddnmodified = 0;
   1205  1.1.1.4      tron 				} else {
   1206  1.1.1.4      tron 
   1207  1.1.1.4      tron 					if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
   1208  1.1.1.4      tron 						LDAP_SUCCESS || group == NULL ) {
   1209  1.1.1.4      tron 						Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
   1210      1.1     lukem 
   1211  1.1.1.4      tron 						op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
   1212  1.1.1.4      tron 						op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
   1213      1.1     lukem 
   1214  1.1.1.5  christos 						attrs_free( attrs );
   1215  1.1.1.4      tron 						ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1216  1.1.1.4      tron 						ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1217  1.1.1.4      tron 						return SLAP_CB_CONTINUE;
   1218  1.1.1.4      tron 					}
   1219  1.1.1.4      tron 
   1220  1.1.1.4      tron 					a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
   1221  1.1.1.4      tron 
   1222  1.1.1.4      tron 					if ( a != NULL ) {
   1223  1.1.1.4      tron 						if ( value_find_ex( age->age_def->agd_member_ad,
   1224  1.1.1.4      tron 								SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   1225  1.1.1.4      tron 								SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
   1226  1.1.1.4      tron 								a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
   1227  1.1.1.4      tron 						{
   1228  1.1.1.4      tron 							is_olddn = 1;
   1229  1.1.1.4      tron 						}
   1230      1.1     lukem 
   1231      1.1     lukem 					}
   1232      1.1     lukem 
   1233  1.1.1.4      tron 					overlay_entry_release_ov( op, group, 0, on );
   1234      1.1     lukem 
   1235  1.1.1.4      tron 				}
   1236      1.1     lukem 
   1237      1.1     lukem 				for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1238      1.1     lukem 					if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
   1239  1.1.1.4      tron 						/* TODO: should retest filter as it could imply conditions on the dn */
   1240      1.1     lukem 						is_newdn = 1;
   1241      1.1     lukem 						break;
   1242      1.1     lukem 					}
   1243      1.1     lukem 				}
   1244      1.1     lukem 
   1245      1.1     lukem 
   1246  1.1.1.4      tron 				if ( is_value_refresh ) {
   1247  1.1.1.4      tron 					if ( is_olddn != is_newdn ) {
   1248  1.1.1.4      tron 						/* group refresh */
   1249  1.1.1.4      tron 						autogroup_delete_member_from_group( op, NULL, NULL, age) ;
   1250  1.1.1.4      tron 
   1251  1.1.1.4      tron 						for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1252  1.1.1.4      tron 							autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
   1253  1.1.1.4      tron 						}
   1254  1.1.1.4      tron 					}
   1255  1.1.1.4      tron 					ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1256  1.1.1.4      tron 					continue;
   1257  1.1.1.4      tron 				}
   1258      1.1     lukem 				if ( is_olddn == 1 && is_newdn == 0 ) {
   1259  1.1.1.4      tron 					if ( ea )
   1260  1.1.1.5  christos 						autogroup_delete_member_values_from_group( op, &new_dn, age, ea );
   1261  1.1.1.4      tron 					else
   1262  1.1.1.4      tron 						autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
   1263      1.1     lukem 				} else
   1264      1.1     lukem 				if ( is_olddn == 0 && is_newdn == 1 ) {
   1265  1.1.1.5  christos 					Entry etmp;
   1266  1.1.1.5  christos 					struct berval odn, ondn;
   1267  1.1.1.5  christos 					etmp.e_name = op->o_req_dn;
   1268  1.1.1.5  christos 					etmp.e_nname = op->o_req_ndn;
   1269  1.1.1.5  christos 					etmp.e_attrs = attrs;
   1270  1.1.1.5  christos 					odn = op->o_dn;
   1271  1.1.1.5  christos 					ondn = op->o_ndn;
   1272  1.1.1.5  christos 					op->o_dn = op->o_bd->be_rootdn;
   1273  1.1.1.5  christos 					op->o_ndn = op->o_bd->be_rootndn;
   1274  1.1.1.5  christos 
   1275      1.1     lukem 					for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
   1276  1.1.1.5  christos 						if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
   1277  1.1.1.5  christos 							if ( ea ) {
   1278  1.1.1.5  christos 								autogroup_add_member_values_to_group( op, &new_dn, age, ea );
   1279  1.1.1.5  christos 							} else
   1280  1.1.1.4      tron 								autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
   1281      1.1     lukem 							break;
   1282      1.1     lukem 						}
   1283      1.1     lukem 					}
   1284  1.1.1.5  christos 					op->o_dn = odn;
   1285  1.1.1.5  christos 					op->o_ndn = ondn;
   1286      1.1     lukem 				} else
   1287      1.1     lukem 				if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
   1288  1.1.1.4      tron 					if ( ea ) {
   1289  1.1.1.4      tron 						/* group refresh */
   1290  1.1.1.4      tron 						autogroup_delete_member_from_group( op, NULL, NULL, age) ;
   1291  1.1.1.4      tron 
   1292  1.1.1.4      tron 						for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1293  1.1.1.4      tron 							autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
   1294  1.1.1.4      tron 						}
   1295  1.1.1.4      tron 					}
   1296  1.1.1.4      tron 					else {
   1297  1.1.1.4      tron 						autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
   1298  1.1.1.4      tron 						autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
   1299  1.1.1.4      tron 					}
   1300      1.1     lukem 				}
   1301      1.1     lukem 
   1302      1.1     lukem 				ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1303      1.1     lukem 			}
   1304      1.1     lukem 
   1305      1.1     lukem 			op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
   1306      1.1     lukem 			op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
   1307      1.1     lukem 
   1308  1.1.1.5  christos 			attrs_free( attrs );
   1309  1.1.1.4      tron 
   1310      1.1     lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1311      1.1     lukem 		}
   1312      1.1     lukem 	}
   1313      1.1     lukem 
   1314      1.1     lukem 	if ( op->o_tag == LDAP_REQ_MODIFY ) {
   1315  1.1.1.5  christos 		if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS  && !oex ) {
   1316  1.1.1.5  christos 			Entry etmp;
   1317  1.1.1.5  christos 			struct berval odn, ondn;
   1318      1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1319      1.1     lukem 
   1320      1.1     lukem 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1321      1.1     lukem 
   1322      1.1     lukem 			if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
   1323      1.1     lukem 				LDAP_SUCCESS || e == NULL ) {
   1324      1.1     lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1325      1.1     lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1326      1.1     lukem 				return SLAP_CB_CONTINUE;
   1327      1.1     lukem 			}
   1328      1.1     lukem 
   1329      1.1     lukem 			a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
   1330      1.1     lukem 
   1331      1.1     lukem 
   1332      1.1     lukem 			if ( a == NULL ) {
   1333      1.1     lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
   1334      1.1     lukem 				overlay_entry_release_ov( op, e, 0, on );
   1335      1.1     lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1336      1.1     lukem 				return SLAP_CB_CONTINUE;
   1337      1.1     lukem 			}
   1338      1.1     lukem 
   1339      1.1     lukem 			/* If we modify a group's memberURL, we have to delete all of it's members,
   1340      1.1     lukem 			   and add them anew, because we cannot tell from which memberURL a member was added. */
   1341      1.1     lukem 			for ( ; agd; agd = agd->agd_next ) {
   1342      1.1     lukem 
   1343      1.1     lukem 				if ( value_find_ex( slap_schema.si_ad_objectClass,
   1344      1.1     lukem 						SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   1345      1.1     lukem 						SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
   1346      1.1     lukem 						a->a_nvals, &agd->agd_oc->soc_cname,
   1347      1.1     lukem 						op->o_tmpmemctx ) == 0 )
   1348      1.1     lukem 				{
   1349      1.1     lukem 					Modifications	*m;
   1350      1.1     lukem 					int		match = 1;
   1351      1.1     lukem 
   1352      1.1     lukem 					m = op->orm_modlist;
   1353      1.1     lukem 
   1354  1.1.1.4      tron 					for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1355      1.1     lukem 						ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1356      1.1     lukem 
   1357      1.1     lukem 						dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
   1358      1.1     lukem 
   1359      1.1     lukem 						if ( match == 0 ) {
   1360      1.1     lukem 							for ( ; m ; m = m->sml_next ) {
   1361      1.1     lukem 								if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
   1362      1.1     lukem 									autogroup_def_t	*group_agd = age->age_def;
   1363      1.1     lukem 									Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
   1364      1.1     lukem 										op->o_req_dn.bv_val, 0, 0);
   1365      1.1     lukem 
   1366      1.1     lukem 									overlay_entry_release_ov( op, e, 0, on );
   1367      1.1     lukem 
   1368      1.1     lukem 									autogroup_delete_member_from_group( op, NULL, NULL, age );
   1369      1.1     lukem 									autogroup_delete_group( agi, age );
   1370      1.1     lukem 
   1371      1.1     lukem 									autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
   1372      1.1     lukem 
   1373      1.1     lukem 									ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1374      1.1     lukem 									return SLAP_CB_CONTINUE;
   1375      1.1     lukem 								}
   1376      1.1     lukem 							}
   1377      1.1     lukem 
   1378      1.1     lukem 							ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1379      1.1     lukem 							break;
   1380      1.1     lukem 						}
   1381      1.1     lukem 
   1382      1.1     lukem 						ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1383      1.1     lukem 					}
   1384      1.1     lukem 
   1385      1.1     lukem 					overlay_entry_release_ov( op, e, 0, on );
   1386      1.1     lukem 					ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1387      1.1     lukem 					return SLAP_CB_CONTINUE;
   1388      1.1     lukem 				}
   1389      1.1     lukem 			}
   1390      1.1     lukem 
   1391  1.1.1.5  christos 			/* When modifying any of the attributes of an entry, we must
   1392      1.1     lukem 			   check if the entry is in any of our groups, and if
   1393      1.1     lukem 			   the modified entry maches any of the filters of that group.
   1394      1.1     lukem 
   1395      1.1     lukem 			   If the entry exists in a group, but the modified attributes do
   1396      1.1     lukem 				not match any of the group's filters, we delete the entry from that group.
   1397      1.1     lukem 			   If the entry doesn't exist in a group, but matches a filter,
   1398      1.1     lukem 				we add it to that group.
   1399      1.1     lukem 			*/
   1400  1.1.1.5  christos 			attrs = attrs_dup( e->e_attrs );
   1401  1.1.1.5  christos 			overlay_entry_release_ov( op, e, 0, on );
   1402  1.1.1.5  christos 			etmp.e_name = op->o_req_dn;
   1403  1.1.1.5  christos 			etmp.e_nname = op->o_req_ndn;
   1404  1.1.1.5  christos 			etmp.e_attrs = attrs;
   1405  1.1.1.5  christos 			odn = op->o_dn;
   1406  1.1.1.5  christos 			ondn = op->o_ndn;
   1407  1.1.1.5  christos 			op->o_dn = op->o_bd->be_rootdn;
   1408  1.1.1.5  christos 			op->o_ndn = op->o_bd->be_rootndn;
   1409  1.1.1.5  christos 
   1410      1.1     lukem 			for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1411      1.1     lukem 				is_olddn = 0;
   1412      1.1     lukem 				is_newdn = 0;
   1413      1.1     lukem 
   1414      1.1     lukem 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1415      1.1     lukem 
   1416  1.1.1.4      tron 				if ( age->age_filter && age->age_filter->agf_anlist ) {
   1417  1.1.1.5  christos 					ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
   1418  1.1.1.4      tron 				}
   1419  1.1.1.4      tron 				else {
   1420  1.1.1.4      tron 					ea = NULL;
   1421  1.1.1.4      tron 				}
   1422  1.1.1.4      tron 
   1423      1.1     lukem 				if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
   1424      1.1     lukem 					LDAP_SUCCESS || group == NULL ) {
   1425      1.1     lukem 					Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
   1426      1.1     lukem 						age->age_dn.bv_val, 0, 0);
   1427      1.1     lukem 
   1428  1.1.1.5  christos 					attrs_free( attrs );
   1429      1.1     lukem 					ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1430      1.1     lukem 					ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1431  1.1.1.5  christos 					op->o_dn = odn;
   1432  1.1.1.5  christos 					op->o_ndn = ondn;
   1433      1.1     lukem 					return SLAP_CB_CONTINUE;
   1434      1.1     lukem 				}
   1435      1.1     lukem 
   1436      1.1     lukem 				a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
   1437      1.1     lukem 
   1438      1.1     lukem 				if ( a != NULL ) {
   1439      1.1     lukem 					if ( value_find_ex( age->age_def->agd_member_ad,
   1440      1.1     lukem 							SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   1441      1.1     lukem 							SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
   1442  1.1.1.4      tron 							a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
   1443      1.1     lukem 					{
   1444      1.1     lukem 						is_olddn = 1;
   1445      1.1     lukem 					}
   1446      1.1     lukem 
   1447      1.1     lukem 				}
   1448      1.1     lukem 
   1449      1.1     lukem 				overlay_entry_release_ov( op, group, 0, on );
   1450      1.1     lukem 
   1451      1.1     lukem 				for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1452      1.1     lukem 					if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
   1453  1.1.1.5  christos 						if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
   1454      1.1     lukem 							is_newdn = 1;
   1455      1.1     lukem 							break;
   1456      1.1     lukem 						}
   1457      1.1     lukem 					}
   1458      1.1     lukem 				}
   1459      1.1     lukem 
   1460      1.1     lukem 				if ( is_olddn == 1 && is_newdn == 0 ) {
   1461  1.1.1.4      tron 					if(ea)
   1462  1.1.1.5  christos 						autogroup_delete_member_values_from_group( op, &op->o_req_dn, age, ea );
   1463  1.1.1.4      tron 					else
   1464  1.1.1.4      tron 						autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
   1465      1.1     lukem 				} else
   1466      1.1     lukem 				if ( is_olddn == 0 && is_newdn == 1 ) {
   1467  1.1.1.4      tron 					if(ea)
   1468  1.1.1.5  christos 						autogroup_add_member_values_to_group( op, &op->o_req_dn, age, ea );
   1469  1.1.1.4      tron 					else
   1470  1.1.1.4      tron 						autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
   1471      1.1     lukem 				}
   1472      1.1     lukem 
   1473      1.1     lukem 				ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1474      1.1     lukem 			}
   1475      1.1     lukem 
   1476  1.1.1.5  christos 			op->o_dn = odn;
   1477  1.1.1.5  christos 			op->o_ndn = ondn;
   1478  1.1.1.5  christos 			attrs_free( attrs );
   1479  1.1.1.4      tron 
   1480      1.1     lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1481      1.1     lukem 		}
   1482      1.1     lukem 	}
   1483      1.1     lukem 
   1484      1.1     lukem 	return SLAP_CB_CONTINUE;
   1485      1.1     lukem }
   1486      1.1     lukem 
   1487      1.1     lukem /*
   1488  1.1.1.4      tron ** Detect if filter contains a memberOf check for dn
   1489  1.1.1.4      tron */
   1490  1.1.1.4      tron static int
   1491  1.1.1.4      tron autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad )
   1492  1.1.1.4      tron {
   1493  1.1.1.4      tron 	int result = 0;
   1494  1.1.1.4      tron 	if ( f == NULL ) return 0;
   1495  1.1.1.4      tron 
   1496  1.1.1.4      tron   	switch ( f->f_choice & SLAPD_FILTER_MASK ) {
   1497  1.1.1.4      tron 		case LDAP_FILTER_AND:
   1498  1.1.1.4      tron 		case LDAP_FILTER_OR:
   1499  1.1.1.4      tron 		case LDAP_FILTER_NOT:
   1500  1.1.1.4      tron 			for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) {
   1501  1.1.1.4      tron 				result = result || autogroup_memberOf_filter( f, dn, memberof_ad );
   1502  1.1.1.4      tron 			}
   1503  1.1.1.4      tron 			break;
   1504  1.1.1.4      tron 		case LDAP_FILTER_EQUALITY:
   1505  1.1.1.4      tron 			result = ( f->f_ava->aa_desc == memberof_ad &&
   1506  1.1.1.4      tron 			           ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 );
   1507  1.1.1.4      tron 			break;
   1508  1.1.1.4      tron 		default:
   1509  1.1.1.4      tron 			break;
   1510  1.1.1.4      tron 	}
   1511  1.1.1.4      tron 
   1512  1.1.1.4      tron 	return result;
   1513  1.1.1.4      tron }
   1514  1.1.1.4      tron 
   1515  1.1.1.4      tron /*
   1516      1.1     lukem ** When modifing a group, we must deny any modifications to the member attribute,
   1517      1.1     lukem ** because the group would be inconsistent.
   1518      1.1     lukem */
   1519      1.1     lukem static int
   1520      1.1     lukem autogroup_modify_entry( Operation *op, SlapReply *rs)
   1521      1.1     lukem {
   1522      1.1     lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
   1523      1.1     lukem 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
   1524      1.1     lukem 	autogroup_def_t		*agd = agi->agi_def;
   1525  1.1.1.4      tron 	autogroup_entry_t	*age;
   1526      1.1     lukem 	Entry			*e;
   1527      1.1     lukem 	Attribute		*a;
   1528  1.1.1.5  christos 	struct berval odn, ondn;
   1529  1.1.1.5  christos 	OpExtra *oex;
   1530      1.1     lukem 
   1531  1.1.1.5  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
   1532  1.1.1.5  christos 		if ( oex->oe_key == (void *)&autogroup )
   1533  1.1.1.5  christos 			return SLAP_CB_CONTINUE;
   1534      1.1     lukem 	}
   1535      1.1     lukem 
   1536      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1537      1.1     lukem 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1538      1.1     lukem 
   1539      1.1     lukem 	if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
   1540      1.1     lukem 		LDAP_SUCCESS || e == NULL ) {
   1541      1.1     lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1542      1.1     lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1543      1.1     lukem 		return SLAP_CB_CONTINUE;
   1544      1.1     lukem 	}
   1545      1.1     lukem 
   1546  1.1.1.5  christos 	odn = op->o_dn;
   1547  1.1.1.5  christos 	ondn = op->o_ndn;
   1548  1.1.1.5  christos 	op->o_dn = op->o_bd->be_rootdn;
   1549  1.1.1.5  christos 	op->o_ndn = op->o_bd->be_rootndn;
   1550  1.1.1.5  christos 
   1551  1.1.1.4      tron 	/* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */
   1552  1.1.1.4      tron 	for ( age = agi->agi_entry; age ; age = age->age_next ) {
   1553  1.1.1.4      tron 		autogroup_filter_t	*agf;
   1554  1.1.1.4      tron 		for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1555  1.1.1.4      tron 			if ( agf->agf_anlist ) {
   1556  1.1.1.4      tron 				Modifications	*m;
   1557  1.1.1.4      tron 				for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
   1558  1.1.1.4      tron 					if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
   1559  1.1.1.4      tron 						if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
   1560  1.1.1.4      tron 							int rc = test_filter( op, e, agf->agf_filter );
   1561  1.1.1.4      tron 							if ( rc == LDAP_COMPARE_TRUE ) {
   1562  1.1.1.4      tron 								age->age_mustrefresh = 1;
   1563  1.1.1.4      tron 							}
   1564  1.1.1.4      tron 						}
   1565  1.1.1.4      tron 					}
   1566  1.1.1.4      tron 				}
   1567  1.1.1.4      tron 			}
   1568  1.1.1.4      tron 
   1569  1.1.1.4      tron 			if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) {
   1570  1.1.1.4      tron 				age->age_mustrefresh = 1;
   1571  1.1.1.4      tron 			}
   1572  1.1.1.4      tron 		}
   1573  1.1.1.4      tron 	}
   1574  1.1.1.5  christos 	op->o_dn = odn;
   1575  1.1.1.5  christos 	op->o_ndn = ondn;
   1576  1.1.1.4      tron 
   1577      1.1     lukem 	a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
   1578      1.1     lukem 
   1579      1.1     lukem 	if ( a == NULL ) {
   1580      1.1     lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
   1581      1.1     lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1582      1.1     lukem 		return SLAP_CB_CONTINUE;
   1583      1.1     lukem 	}
   1584      1.1     lukem 
   1585      1.1     lukem 
   1586      1.1     lukem 	for ( ; agd; agd = agd->agd_next ) {
   1587      1.1     lukem 
   1588      1.1     lukem 		if ( value_find_ex( slap_schema.si_ad_objectClass,
   1589      1.1     lukem 				SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   1590      1.1     lukem 				SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
   1591      1.1     lukem 				a->a_nvals, &agd->agd_oc->soc_cname,
   1592      1.1     lukem 				op->o_tmpmemctx ) == 0 )
   1593      1.1     lukem 		{
   1594      1.1     lukem 			Modifications	*m;
   1595      1.1     lukem 			int		match = 1;
   1596      1.1     lukem 
   1597      1.1     lukem 			m = op->orm_modlist;
   1598      1.1     lukem 
   1599  1.1.1.4      tron 			for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1600      1.1     lukem 				dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
   1601      1.1     lukem 
   1602      1.1     lukem 				if ( match == 0 ) {
   1603      1.1     lukem 					for ( ; m ; m = m->sml_next ) {
   1604      1.1     lukem 						if ( m->sml_desc == age->age_def->agd_member_ad ) {
   1605      1.1     lukem 							overlay_entry_release_ov( op, e, 0, on );
   1606      1.1     lukem 							ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1607      1.1     lukem 							Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
   1608      1.1     lukem 							send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
   1609      1.1     lukem 							return LDAP_CONSTRAINT_VIOLATION;
   1610      1.1     lukem 						}
   1611      1.1     lukem 					}
   1612      1.1     lukem 					break;
   1613      1.1     lukem 				}
   1614      1.1     lukem 			}
   1615      1.1     lukem 
   1616  1.1.1.5  christos 			/* an entry may only have one dynamic group class */
   1617  1.1.1.5  christos 			break;
   1618      1.1     lukem 		}
   1619      1.1     lukem 	}
   1620      1.1     lukem 
   1621      1.1     lukem 	overlay_entry_release_ov( op, e, 0, on );
   1622      1.1     lukem 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1623      1.1     lukem 	return SLAP_CB_CONTINUE;
   1624      1.1     lukem }
   1625      1.1     lukem 
   1626  1.1.1.4      tron /*
   1627  1.1.1.4      tron ** Detect if the olddn is part of a group and so if the group should be refreshed
   1628  1.1.1.4      tron */
   1629  1.1.1.4      tron static int
   1630  1.1.1.4      tron autogroup_modrdn_entry( Operation *op, SlapReply *rs)
   1631  1.1.1.4      tron {
   1632  1.1.1.4      tron 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
   1633  1.1.1.4      tron 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
   1634  1.1.1.4      tron 	autogroup_entry_t	*age;
   1635  1.1.1.4      tron 	Entry			*e;
   1636  1.1.1.5  christos 	struct berval odn, ondn;
   1637  1.1.1.5  christos 	OpExtra *oex;
   1638  1.1.1.4      tron 
   1639  1.1.1.5  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
   1640  1.1.1.5  christos 		if ( oex->oe_key == (void *)&autogroup )
   1641  1.1.1.5  christos 			return SLAP_CB_CONTINUE;
   1642  1.1.1.4      tron 	}
   1643  1.1.1.4      tron 
   1644  1.1.1.4      tron 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1645  1.1.1.4      tron 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1646  1.1.1.4      tron 
   1647  1.1.1.4      tron 	if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
   1648  1.1.1.4      tron 		LDAP_SUCCESS || e == NULL ) {
   1649  1.1.1.4      tron 		Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1650  1.1.1.4      tron 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1651  1.1.1.4      tron 		return SLAP_CB_CONTINUE;
   1652  1.1.1.4      tron 	}
   1653  1.1.1.4      tron 
   1654  1.1.1.5  christos 	odn = op->o_dn;
   1655  1.1.1.5  christos 	ondn = op->o_ndn;
   1656  1.1.1.5  christos 	op->o_dn = op->o_bd->be_rootdn;
   1657  1.1.1.5  christos 	op->o_ndn = op->o_bd->be_rootndn;
   1658  1.1.1.5  christos 
   1659  1.1.1.4      tron 	/* Must check if a dn is modified */
   1660  1.1.1.4      tron 	for ( age = agi->agi_entry; age ; age = age->age_next ) {
   1661  1.1.1.4      tron 		autogroup_filter_t	*agf;
   1662  1.1.1.4      tron 		for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1663  1.1.1.4      tron 			if ( agf->agf_anlist ) {
   1664  1.1.1.4      tron 				if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
   1665  1.1.1.4      tron 					int rc = test_filter( op, e, agf->agf_filter );
   1666  1.1.1.4      tron 					if ( rc == LDAP_COMPARE_TRUE ) {
   1667  1.1.1.4      tron 						age->age_modrdn_olddnmodified = 1;
   1668  1.1.1.4      tron 					}
   1669  1.1.1.4      tron 				}
   1670  1.1.1.4      tron 			}
   1671  1.1.1.4      tron 		}
   1672  1.1.1.4      tron 	}
   1673  1.1.1.5  christos 	op->o_dn = odn;
   1674  1.1.1.5  christos 	op->o_ndn = ondn;
   1675  1.1.1.4      tron 
   1676  1.1.1.4      tron 	overlay_entry_release_ov( op, e, 0, on );
   1677  1.1.1.4      tron 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1678  1.1.1.4      tron 	return SLAP_CB_CONTINUE;
   1679  1.1.1.4      tron }
   1680  1.1.1.4      tron 
   1681      1.1     lukem /*
   1682      1.1     lukem ** Builds a filter for searching for the
   1683      1.1     lukem ** group entries, according to the objectClass.
   1684      1.1     lukem */
   1685      1.1     lukem static int
   1686      1.1     lukem autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
   1687      1.1     lukem {
   1688      1.1     lukem 	char	*ptr;
   1689      1.1     lukem 
   1690      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
   1691      1.1     lukem 
   1692      1.1     lukem 	op->ors_filterstr.bv_len = STRLENOF( "(=)" )
   1693      1.1     lukem 			+ slap_schema.si_ad_objectClass->ad_cname.bv_len
   1694      1.1     lukem 			+ agd->agd_oc->soc_cname.bv_len;
   1695      1.1     lukem 	ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
   1696      1.1     lukem 	*ptr++ = '(';
   1697      1.1     lukem 	ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
   1698      1.1     lukem 	*ptr++ = '=';
   1699      1.1     lukem 	ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
   1700      1.1     lukem 	*ptr++ = ')';
   1701      1.1     lukem 	*ptr = '\0';
   1702      1.1     lukem 
   1703      1.1     lukem 	op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
   1704      1.1     lukem 
   1705      1.1     lukem 	assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
   1706      1.1     lukem 
   1707      1.1     lukem 	return 0;
   1708      1.1     lukem }
   1709      1.1     lukem 
   1710      1.1     lukem enum {
   1711      1.1     lukem 	AG_ATTRSET = 1,
   1712  1.1.1.4      tron 	AG_MEMBER_OF_AD,
   1713      1.1     lukem 	AG_LAST
   1714      1.1     lukem };
   1715      1.1     lukem 
   1716      1.1     lukem static ConfigDriver	ag_cfgen;
   1717      1.1     lukem 
   1718      1.1     lukem static ConfigTable agcfg[] = {
   1719      1.1     lukem 	{ "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
   1720  1.1.1.5  christos 		4, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
   1721      1.1     lukem 		"( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
   1722      1.1     lukem 			"DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
   1723      1.1     lukem 			"EQUALITY caseIgnoreMatch "
   1724      1.1     lukem 			"SYNTAX OMsDirectoryString "
   1725      1.1     lukem 			"X-ORDERED 'VALUES' )",
   1726      1.1     lukem 			NULL, NULL },
   1727  1.1.1.4      tron 
   1728  1.1.1.4      tron 	{ "autogroup-memberof-ad", "memberOf attribute",
   1729  1.1.1.4      tron 		2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen,
   1730  1.1.1.4      tron 		"( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' "
   1731  1.1.1.4      tron 			"DESC 'memberOf attribute' "
   1732  1.1.1.4      tron 			"SYNTAX OMsDirectoryString SINGLE-VALUE )",
   1733  1.1.1.4      tron 			NULL, NULL },
   1734  1.1.1.4      tron 
   1735      1.1     lukem 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
   1736      1.1     lukem };
   1737      1.1     lukem 
   1738      1.1     lukem static ConfigOCs agocs[] = {
   1739      1.1     lukem 	{ "( OLcfgCtOc:2.1 "
   1740      1.1     lukem 		"NAME 'olcAutomaticGroups' "
   1741      1.1     lukem 		"DESC 'Automatic groups configuration' "
   1742      1.1     lukem 		"SUP olcOverlayConfig "
   1743  1.1.1.4      tron 		"MAY ( "
   1744  1.1.1.4      tron 			"olcAGattrSet "
   1745  1.1.1.4      tron 			"$ olcAGmemberOfAd "
   1746  1.1.1.4      tron 		    ")"
   1747  1.1.1.4      tron 	  ")",
   1748      1.1     lukem 		Cft_Overlay, agcfg, NULL, NULL },
   1749      1.1     lukem 	{ NULL, 0, NULL }
   1750      1.1     lukem };
   1751      1.1     lukem 
   1752      1.1     lukem 
   1753      1.1     lukem static int
   1754      1.1     lukem ag_cfgen( ConfigArgs *c )
   1755      1.1     lukem {
   1756      1.1     lukem 	slap_overinst		*on = (slap_overinst *)c->bi;
   1757      1.1     lukem 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
   1758      1.1     lukem 	autogroup_def_t		*agd;
   1759      1.1     lukem 	autogroup_entry_t	*age;
   1760      1.1     lukem 
   1761      1.1     lukem 	int rc = 0, i;
   1762      1.1     lukem 
   1763      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
   1764      1.1     lukem 
   1765      1.1     lukem 	if( agi == NULL ) {
   1766      1.1     lukem 		agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
   1767      1.1     lukem 		ldap_pvt_thread_mutex_init( &agi->agi_mutex );
   1768      1.1     lukem 		agi->agi_def = NULL;
   1769      1.1     lukem 		agi->agi_entry = NULL;
   1770      1.1     lukem 		on->on_bi.bi_private = (void *)agi;
   1771      1.1     lukem 	}
   1772      1.1     lukem 
   1773      1.1     lukem 	agd = agi->agi_def;
   1774      1.1     lukem 	age = agi->agi_entry;
   1775      1.1     lukem 
   1776      1.1     lukem 	if ( c->op == SLAP_CONFIG_EMIT ) {
   1777      1.1     lukem 
   1778  1.1.1.4      tron 		switch( c->type ){
   1779  1.1.1.4      tron 		case AG_ATTRSET:
   1780  1.1.1.4      tron 			for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
   1781  1.1.1.4      tron 				struct berval	bv;
   1782  1.1.1.4      tron 				char		*ptr = c->cr_msg;
   1783  1.1.1.4      tron 
   1784  1.1.1.4      tron 				assert(agd->agd_oc != NULL);
   1785  1.1.1.4      tron 				assert(agd->agd_member_url_ad != NULL);
   1786  1.1.1.4      tron 				assert(agd->agd_member_ad != NULL);
   1787  1.1.1.4      tron 
   1788  1.1.1.4      tron 				ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1789  1.1.1.4      tron 					SLAP_X_ORDERED_FMT "%s %s %s", i,
   1790  1.1.1.4      tron 					agd->agd_oc->soc_cname.bv_val,
   1791  1.1.1.4      tron 					agd->agd_member_url_ad->ad_cname.bv_val,
   1792  1.1.1.4      tron 					agd->agd_member_ad->ad_cname.bv_val );
   1793  1.1.1.4      tron 
   1794  1.1.1.4      tron 				bv.bv_val = c->cr_msg;
   1795  1.1.1.4      tron 				bv.bv_len = ptr - bv.bv_val;
   1796  1.1.1.4      tron 				value_add_one ( &c->rvalue_vals, &bv );
   1797  1.1.1.4      tron 
   1798  1.1.1.4      tron 			}
   1799  1.1.1.4      tron 			break;
   1800  1.1.1.4      tron 
   1801  1.1.1.4      tron 		case AG_MEMBER_OF_AD:
   1802  1.1.1.4      tron 			if ( agi->agi_memberof_ad != NULL ){
   1803  1.1.1.4      tron 				value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname );
   1804  1.1.1.4      tron 			}
   1805  1.1.1.4      tron 			break;
   1806      1.1     lukem 
   1807  1.1.1.4      tron 		default:
   1808  1.1.1.4      tron 			assert( 0 );
   1809  1.1.1.4      tron 			return 1;
   1810  1.1.1.4      tron       }
   1811      1.1     lukem 
   1812      1.1     lukem 		return rc;
   1813      1.1     lukem 
   1814      1.1     lukem 	}else if ( c->op == LDAP_MOD_DELETE ) {
   1815      1.1     lukem 		if ( c->valx < 0) {
   1816      1.1     lukem 			autogroup_def_t 		*agd_next;
   1817      1.1     lukem 			autogroup_entry_t	*age_next;
   1818      1.1     lukem 			autogroup_filter_t	*agf = age->age_filter,
   1819      1.1     lukem 						*agf_next;
   1820      1.1     lukem 
   1821      1.1     lukem 			for ( agd_next = agd; agd_next; agd = agd_next ) {
   1822      1.1     lukem 				agd_next = agd->agd_next;
   1823      1.1     lukem 
   1824      1.1     lukem 				ch_free( agd );
   1825      1.1     lukem 			}
   1826      1.1     lukem 
   1827      1.1     lukem 			for ( age_next = age ; age_next ; age = age_next ) {
   1828      1.1     lukem 				age_next = age->age_next;
   1829      1.1     lukem 
   1830      1.1     lukem 				ch_free( age->age_dn.bv_val );
   1831      1.1     lukem 				ch_free( age->age_ndn.bv_val );
   1832      1.1     lukem 
   1833      1.1     lukem 				for( agf_next = agf ; agf_next ; agf = agf_next ){
   1834      1.1     lukem 					agf_next = agf->agf_next;
   1835      1.1     lukem 
   1836      1.1     lukem 					filter_free( agf->agf_filter );
   1837      1.1     lukem 					ch_free( agf->agf_filterstr.bv_val );
   1838      1.1     lukem 					ch_free( agf->agf_dn.bv_val );
   1839      1.1     lukem 					ch_free( agf->agf_ndn.bv_val );
   1840  1.1.1.4      tron 					anlist_free( agf->agf_anlist, 1, NULL );
   1841  1.1.1.4      tron 					ch_free( agf );
   1842      1.1     lukem 				}
   1843      1.1     lukem 
   1844      1.1     lukem 				ldap_pvt_thread_mutex_init( &age->age_mutex );
   1845      1.1     lukem 				ch_free( age );
   1846      1.1     lukem 			}
   1847      1.1     lukem 
   1848      1.1     lukem 			ch_free( agi );
   1849      1.1     lukem 			on->on_bi.bi_private = NULL;
   1850      1.1     lukem 
   1851      1.1     lukem 		} else {
   1852      1.1     lukem 			autogroup_def_t		**agdp;
   1853      1.1     lukem 			autogroup_entry_t	*age_next, *age_prev;
   1854      1.1     lukem 			autogroup_filter_t	*agf,
   1855      1.1     lukem 						*agf_next;
   1856      1.1     lukem 
   1857      1.1     lukem 			for ( i = 0, agdp = &agi->agi_def;
   1858      1.1     lukem 				i < c->valx; i++ )
   1859      1.1     lukem 			{
   1860      1.1     lukem 				if ( *agdp == NULL) {
   1861      1.1     lukem 					return 1;
   1862      1.1     lukem 				}
   1863      1.1     lukem 				agdp = &(*agdp)->agd_next;
   1864      1.1     lukem 			}
   1865      1.1     lukem 
   1866      1.1     lukem 			agd = *agdp;
   1867      1.1     lukem 			*agdp = agd->agd_next;
   1868      1.1     lukem 
   1869      1.1     lukem 			for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
   1870      1.1     lukem 				age_next = age->age_next;
   1871      1.1     lukem 
   1872      1.1     lukem 				if( age->age_def == agd ) {
   1873      1.1     lukem 					agf = age->age_filter;
   1874      1.1     lukem 
   1875      1.1     lukem 					ch_free( age->age_dn.bv_val );
   1876      1.1     lukem 					ch_free( age->age_ndn.bv_val );
   1877      1.1     lukem 
   1878      1.1     lukem 					for ( agf_next = agf; agf_next ; agf = agf_next ) {
   1879      1.1     lukem 						agf_next = agf->agf_next;
   1880      1.1     lukem 						filter_free( agf->agf_filter );
   1881      1.1     lukem 						ch_free( agf->agf_filterstr.bv_val );
   1882      1.1     lukem 						ch_free( agf->agf_dn.bv_val );
   1883      1.1     lukem 						ch_free( agf->agf_ndn.bv_val );
   1884  1.1.1.4      tron 						anlist_free( agf->agf_anlist, 1, NULL );
   1885  1.1.1.4      tron 						ch_free( agf );
   1886      1.1     lukem 					}
   1887      1.1     lukem 
   1888      1.1     lukem 					ldap_pvt_thread_mutex_destroy( &age->age_mutex );
   1889      1.1     lukem 					ch_free( age );
   1890      1.1     lukem 
   1891      1.1     lukem 					age = age_prev;
   1892      1.1     lukem 
   1893      1.1     lukem 					if( age_prev != NULL ) {
   1894      1.1     lukem 						age_prev->age_next = age_next;
   1895      1.1     lukem 					}
   1896      1.1     lukem 				}
   1897      1.1     lukem 			}
   1898      1.1     lukem 
   1899      1.1     lukem 			ch_free( agd );
   1900      1.1     lukem 			agd = agi->agi_def;
   1901      1.1     lukem 
   1902      1.1     lukem 		}
   1903      1.1     lukem 
   1904      1.1     lukem 		return rc;
   1905      1.1     lukem 	}
   1906      1.1     lukem 
   1907      1.1     lukem 	switch(c->type){
   1908      1.1     lukem 	case AG_ATTRSET: {
   1909      1.1     lukem 		autogroup_def_t		**agdp,
   1910      1.1     lukem 					*agd_next = NULL;
   1911      1.1     lukem 		ObjectClass		*oc = NULL;
   1912      1.1     lukem 		AttributeDescription	*member_url_ad = NULL,
   1913      1.1     lukem 					*member_ad = NULL;
   1914      1.1     lukem 		const char		*text;
   1915      1.1     lukem 
   1916      1.1     lukem 
   1917      1.1     lukem 		oc = oc_find( c->argv[ 1 ] );
   1918      1.1     lukem 		if( oc == NULL ){
   1919      1.1     lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1920      1.1     lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1921      1.1     lukem 				"unable to find ObjectClass \"%s\"",
   1922      1.1     lukem 				c->argv[ 1 ] );
   1923      1.1     lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1924      1.1     lukem 				c->log, c->cr_msg, 0 );
   1925      1.1     lukem 			return 1;
   1926      1.1     lukem 		}
   1927      1.1     lukem 
   1928      1.1     lukem 
   1929      1.1     lukem 		rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
   1930      1.1     lukem 		if( rc != LDAP_SUCCESS ) {
   1931      1.1     lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1932      1.1     lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1933      1.1     lukem 				"unable to find AttributeDescription \"%s\"",
   1934      1.1     lukem 				c->argv[ 2 ] );
   1935      1.1     lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1936      1.1     lukem 				c->log, c->cr_msg, 0 );
   1937      1.1     lukem 			return 1;
   1938      1.1     lukem 		}
   1939      1.1     lukem 
   1940      1.1     lukem 		if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
   1941      1.1     lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1942      1.1     lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1943      1.1     lukem 				"AttributeDescription \"%s\" ",
   1944      1.1     lukem 				"must be of a subtype \"labeledURI\"",
   1945      1.1     lukem 				c->argv[ 2 ] );
   1946      1.1     lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1947      1.1     lukem 				c->log, c->cr_msg, 0 );
   1948      1.1     lukem 			return 1;
   1949      1.1     lukem 		}
   1950      1.1     lukem 
   1951      1.1     lukem 		rc = slap_str2ad( c->argv[3], &member_ad, &text );
   1952      1.1     lukem 		if( rc != LDAP_SUCCESS ) {
   1953      1.1     lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1954      1.1     lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1955      1.1     lukem 				"unable to find AttributeDescription \"%s\"",
   1956      1.1     lukem 				c->argv[ 3 ] );
   1957      1.1     lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1958      1.1     lukem 				c->log, c->cr_msg, 0 );
   1959      1.1     lukem 			return 1;
   1960      1.1     lukem 		}
   1961      1.1     lukem 
   1962      1.1     lukem 		for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
   1963      1.1     lukem 			/* The same URL attribute / member attribute pair
   1964      1.1     lukem 			* cannot be repeated */
   1965      1.1     lukem 
   1966      1.1     lukem 			if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
   1967      1.1     lukem 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1968      1.1     lukem 					"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1969      1.1     lukem 					"URL attributeDescription \"%s\" already mapped",
   1970      1.1     lukem 					member_ad->ad_cname.bv_val );
   1971      1.1     lukem 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1972      1.1     lukem 					c->log, c->cr_msg, 0 );
   1973      1.1     lukem /*				return 1; //warning*/
   1974      1.1     lukem 			}
   1975      1.1     lukem 		}
   1976      1.1     lukem 
   1977      1.1     lukem 		if ( c->valx > 0 ) {
   1978      1.1     lukem 			int	i;
   1979      1.1     lukem 
   1980      1.1     lukem 			for ( i = 0, agdp = &agi->agi_def ;
   1981      1.1     lukem 				i < c->valx; i++ )
   1982      1.1     lukem 			{
   1983      1.1     lukem 				if ( *agdp == NULL ) {
   1984      1.1     lukem 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1985      1.1     lukem 						"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1986      1.1     lukem 						"invalid index {%d}",
   1987      1.1     lukem 						c->valx );
   1988      1.1     lukem 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1989      1.1     lukem 						c->log, c->cr_msg, 0 );
   1990      1.1     lukem 
   1991      1.1     lukem 					return 1;
   1992      1.1     lukem 				}
   1993      1.1     lukem 				agdp = &(*agdp)->agd_next;
   1994      1.1     lukem 			}
   1995      1.1     lukem 			agd_next = *agdp;
   1996      1.1     lukem 
   1997      1.1     lukem 		} else {
   1998      1.1     lukem 			for ( agdp = &agi->agi_def; *agdp;
   1999      1.1     lukem 				agdp = &(*agdp)->agd_next )
   2000      1.1     lukem 				/* goto last */;
   2001      1.1     lukem 		}
   2002      1.1     lukem 
   2003      1.1     lukem 		*agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
   2004      1.1     lukem 
   2005      1.1     lukem 		(*agdp)->agd_oc = oc;
   2006      1.1     lukem 		(*agdp)->agd_member_url_ad = member_url_ad;
   2007      1.1     lukem 		(*agdp)->agd_member_ad = member_ad;
   2008      1.1     lukem 		(*agdp)->agd_next = agd_next;
   2009      1.1     lukem 
   2010  1.1.1.4      tron 		} break;
   2011  1.1.1.4      tron 
   2012  1.1.1.4      tron 	case AG_MEMBER_OF_AD: {
   2013  1.1.1.4      tron 		AttributeDescription *memberof_ad = NULL;
   2014  1.1.1.4      tron 		const char     *text;
   2015  1.1.1.4      tron 
   2016  1.1.1.4      tron 		rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text );
   2017  1.1.1.4      tron 		if( rc != LDAP_SUCCESS ) {
   2018  1.1.1.4      tron 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   2019  1.1.1.4      tron 				"\"autogroup-memberof-ad <memberof-ad>\": "
   2020  1.1.1.4      tron 				"unable to find AttributeDescription \"%s\"",
   2021  1.1.1.4      tron 				c->argv[ 1 ] );
   2022  1.1.1.4      tron 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   2023  1.1.1.4      tron 				c->log, c->cr_msg, 0 );
   2024  1.1.1.4      tron 			return 1;
   2025  1.1.1.4      tron 		}
   2026  1.1.1.4      tron 
   2027  1.1.1.4      tron 		if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX )    /* e.g. "member" */
   2028  1.1.1.4      tron 		     && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) )  /* e.g. "uniqueMember" */
   2029  1.1.1.4      tron 		{
   2030  1.1.1.4      tron 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   2031  1.1.1.4      tron 				"memberof attribute=\"%s\" must either "
   2032  1.1.1.4      tron 				"have DN (%s) or nameUID (%s) syntax",
   2033  1.1.1.4      tron 				c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
   2034  1.1.1.4      tron 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   2035  1.1.1.4      tron 				c->log, c->cr_msg, 0 );
   2036  1.1.1.4      tron 			return 1;
   2037  1.1.1.4      tron 		}
   2038  1.1.1.4      tron 
   2039  1.1.1.4      tron 		agi->agi_memberof_ad = memberof_ad;
   2040      1.1     lukem 
   2041      1.1     lukem 		} break;
   2042      1.1     lukem 
   2043      1.1     lukem 	default:
   2044      1.1     lukem 		rc = 1;
   2045      1.1     lukem 		break;
   2046      1.1     lukem 	}
   2047      1.1     lukem 
   2048      1.1     lukem 	return rc;
   2049      1.1     lukem }
   2050      1.1     lukem 
   2051  1.1.1.4      tron extern int slapMode;
   2052  1.1.1.4      tron 
   2053      1.1     lukem /*
   2054      1.1     lukem ** Do a search for all the groups in the
   2055      1.1     lukem ** database, and add them to out internal list.
   2056      1.1     lukem */
   2057      1.1     lukem static int
   2058      1.1     lukem autogroup_db_open(
   2059      1.1     lukem 	BackendDB	*be,
   2060      1.1     lukem 	ConfigReply	*cr )
   2061      1.1     lukem {
   2062  1.1.1.2     lukem 	slap_overinst			*on = (slap_overinst *) be->bd_info;
   2063      1.1     lukem 	autogroup_info_t		*agi = on->on_bi.bi_private;
   2064      1.1     lukem 	autogroup_def_t		*agd;
   2065      1.1     lukem 	autogroup_sc_t		ags;
   2066      1.1     lukem 	Operation		*op;
   2067      1.1     lukem 	slap_callback		cb = { 0 };
   2068      1.1     lukem 
   2069      1.1     lukem 	void				*thrctx = ldap_pvt_thread_pool_context();
   2070      1.1     lukem 	Connection			conn = { 0 };
   2071      1.1     lukem 	OperationBuffer 	opbuf;
   2072      1.1     lukem 
   2073      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
   2074      1.1     lukem 
   2075  1.1.1.4      tron 	if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
   2076  1.1.1.2     lukem 		return 0;
   2077  1.1.1.2     lukem 	}
   2078  1.1.1.2     lukem 
   2079      1.1     lukem 	connection_fake_init( &conn, &opbuf, thrctx );
   2080      1.1     lukem 	op = &opbuf.ob_op;
   2081      1.1     lukem 
   2082      1.1     lukem 	op->ors_attrsonly = 0;
   2083      1.1     lukem 	op->o_tag = LDAP_REQ_SEARCH;
   2084      1.1     lukem 	op->o_dn = be->be_rootdn;
   2085      1.1     lukem 	op->o_ndn = be->be_rootndn;
   2086      1.1     lukem 
   2087      1.1     lukem 	op->o_req_dn = be->be_suffix[0];
   2088      1.1     lukem 	op->o_req_ndn = be->be_nsuffix[0];
   2089      1.1     lukem 
   2090      1.1     lukem 	op->ors_scope = LDAP_SCOPE_SUBTREE;
   2091      1.1     lukem 	op->ors_deref = LDAP_DEREF_NEVER;
   2092      1.1     lukem 	op->ors_limit = NULL;
   2093      1.1     lukem 	op->ors_tlimit = SLAP_NO_LIMIT;
   2094      1.1     lukem 	op->ors_slimit = SLAP_NO_LIMIT;
   2095      1.1     lukem 	op->ors_attrs =  slap_anlist_no_attrs;
   2096  1.1.1.5  christos 	op->o_do_not_cache = 1;
   2097      1.1     lukem 
   2098  1.1.1.2     lukem 	op->o_bd = be;
   2099  1.1.1.2     lukem 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
   2100  1.1.1.2     lukem 
   2101  1.1.1.2     lukem 	ags.ags_info = agi;
   2102  1.1.1.2     lukem 	cb.sc_private = &ags;
   2103  1.1.1.2     lukem 	cb.sc_response = autogroup_group_add_cb;
   2104  1.1.1.2     lukem 	cb.sc_cleanup = NULL;
   2105  1.1.1.2     lukem 	cb.sc_next = NULL;
   2106  1.1.1.2     lukem 
   2107  1.1.1.2     lukem 	op->o_callback = &cb;
   2108      1.1     lukem 
   2109      1.1     lukem 	for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
   2110  1.1.1.4      tron 		SlapReply	rs = { REP_RESULT };
   2111      1.1     lukem 
   2112      1.1     lukem 		autogroup_build_def_filter(agd, op);
   2113      1.1     lukem 
   2114      1.1     lukem 		ags.ags_def = agd;
   2115      1.1     lukem 
   2116      1.1     lukem 		op->o_bd->be_search( op, &rs );
   2117      1.1     lukem 
   2118  1.1.1.2     lukem 		filter_free_x( op, op->ors_filter, 1 );
   2119      1.1     lukem 		op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
   2120      1.1     lukem 	}
   2121      1.1     lukem 
   2122  1.1.1.4      tron 	if( ! agi->agi_memberof_ad ){
   2123  1.1.1.4      tron 		int			rc;
   2124  1.1.1.4      tron 		const char		*text = NULL;
   2125  1.1.1.4      tron 
   2126  1.1.1.4      tron 		rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text );
   2127  1.1.1.4      tron 		if ( rc != LDAP_SUCCESS ) {
   2128  1.1.1.4      tron 			Debug( LDAP_DEBUG_ANY, "autogroup_db_open: "
   2129  1.1.1.4      tron 			"unable to find attribute=\"%s\": %s (%d)\n",
   2130  1.1.1.4      tron 			SLAPD_MEMBEROF_ATTR, text, rc );
   2131  1.1.1.4      tron 			return rc;
   2132  1.1.1.4      tron 		}
   2133  1.1.1.4      tron 	}
   2134  1.1.1.4      tron 
   2135      1.1     lukem 	return 0;
   2136      1.1     lukem }
   2137      1.1     lukem 
   2138      1.1     lukem static int
   2139      1.1     lukem autogroup_db_close(
   2140      1.1     lukem 	BackendDB	*be,
   2141      1.1     lukem 	ConfigReply	*cr )
   2142      1.1     lukem {
   2143      1.1     lukem 	slap_overinst			*on = (slap_overinst *) be->bd_info;
   2144      1.1     lukem 
   2145      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
   2146      1.1     lukem 
   2147      1.1     lukem 	if ( on->on_bi.bi_private ) {
   2148      1.1     lukem 		autogroup_info_t		*agi = on->on_bi.bi_private;
   2149      1.1     lukem 		autogroup_entry_t	*age = agi->agi_entry,
   2150      1.1     lukem 					*age_next;
   2151      1.1     lukem 		autogroup_filter_t	*agf, *agf_next;
   2152      1.1     lukem 
   2153      1.1     lukem 		for ( age_next = age; age_next; age = age_next ) {
   2154      1.1     lukem 			age_next = age->age_next;
   2155      1.1     lukem 
   2156      1.1     lukem 			ch_free( age->age_dn.bv_val );
   2157      1.1     lukem 			ch_free( age->age_ndn.bv_val );
   2158      1.1     lukem 
   2159      1.1     lukem 			agf = age->age_filter;
   2160      1.1     lukem 
   2161      1.1     lukem 			for ( agf_next = agf; agf_next; agf = agf_next ) {
   2162      1.1     lukem 				agf_next = agf->agf_next;
   2163      1.1     lukem 
   2164      1.1     lukem 				filter_free( agf->agf_filter );
   2165      1.1     lukem 				ch_free( agf->agf_filterstr.bv_val );
   2166      1.1     lukem 				ch_free( agf->agf_dn.bv_val );
   2167      1.1     lukem 				ch_free( agf->agf_ndn.bv_val );
   2168  1.1.1.4      tron 				anlist_free( agf->agf_anlist, 1, NULL );
   2169      1.1     lukem 				ch_free( agf );
   2170      1.1     lukem 			}
   2171      1.1     lukem 
   2172      1.1     lukem 			ldap_pvt_thread_mutex_destroy( &age->age_mutex );
   2173      1.1     lukem 			ch_free( age );
   2174      1.1     lukem 		}
   2175      1.1     lukem 	}
   2176      1.1     lukem 
   2177      1.1     lukem 	return 0;
   2178      1.1     lukem }
   2179      1.1     lukem 
   2180      1.1     lukem static int
   2181      1.1     lukem autogroup_db_destroy(
   2182      1.1     lukem 	BackendDB	*be,
   2183      1.1     lukem 	ConfigReply	*cr )
   2184      1.1     lukem {
   2185      1.1     lukem 	slap_overinst			*on = (slap_overinst *) be->bd_info;
   2186      1.1     lukem 
   2187      1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
   2188      1.1     lukem 
   2189      1.1     lukem 	if ( on->on_bi.bi_private ) {
   2190      1.1     lukem 		autogroup_info_t		*agi = on->on_bi.bi_private;
   2191      1.1     lukem 		autogroup_def_t		*agd = agi->agi_def,
   2192      1.1     lukem 					*agd_next;
   2193      1.1     lukem 
   2194      1.1     lukem 		for ( agd_next = agd; agd_next; agd = agd_next ) {
   2195      1.1     lukem 			agd_next = agd->agd_next;
   2196      1.1     lukem 
   2197      1.1     lukem 			ch_free( agd );
   2198      1.1     lukem 		}
   2199      1.1     lukem 
   2200      1.1     lukem 		ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
   2201      1.1     lukem 		ch_free( agi );
   2202      1.1     lukem 	}
   2203      1.1     lukem 
   2204      1.1     lukem 	return 0;
   2205      1.1     lukem }
   2206      1.1     lukem 
   2207      1.1     lukem static
   2208      1.1     lukem int
   2209      1.1     lukem autogroup_initialize(void)
   2210      1.1     lukem {
   2211      1.1     lukem 	int		rc = 0;
   2212      1.1     lukem 	autogroup.on_bi.bi_type = "autogroup";
   2213      1.1     lukem 
   2214      1.1     lukem 	autogroup.on_bi.bi_db_open = autogroup_db_open;
   2215      1.1     lukem 	autogroup.on_bi.bi_db_close = autogroup_db_close;
   2216      1.1     lukem 	autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
   2217      1.1     lukem 
   2218      1.1     lukem 	autogroup.on_bi.bi_op_add = autogroup_add_entry;
   2219      1.1     lukem 	autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
   2220      1.1     lukem 	autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
   2221  1.1.1.4      tron 	autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
   2222      1.1     lukem 
   2223      1.1     lukem 	autogroup.on_response = autogroup_response;
   2224      1.1     lukem 
   2225      1.1     lukem 	autogroup.on_bi.bi_cf_ocs = agocs;
   2226      1.1     lukem 
   2227      1.1     lukem 	rc = config_register_schema( agcfg, agocs );
   2228      1.1     lukem 	if ( rc ) {
   2229      1.1     lukem 		return rc;
   2230      1.1     lukem 	}
   2231      1.1     lukem 
   2232      1.1     lukem 	return overlay_register( &autogroup );
   2233      1.1     lukem }
   2234      1.1     lukem 
   2235      1.1     lukem int
   2236      1.1     lukem init_module( int argc, char *argv[] )
   2237      1.1     lukem {
   2238      1.1     lukem 	return autogroup_initialize();
   2239      1.1     lukem }
   2240