Home | History | Annotate | Line # | Download | only in autogroup
autogroup.c revision 1.1.1.2
      1  1.1.1.2  lukem /*	$NetBSD: autogroup.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
      2  1.1.1.2  lukem 
      3      1.1  lukem /* autogroup.c - automatic group overlay */
      4  1.1.1.2  lukem /* OpenLDAP: pkg/ldap/contrib/slapd-modules/autogroup/autogroup.c,v 1.2.2.5 2009/09/29 21:52:13 quanah Exp */
      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.2  lukem  * Copyright 2007-2009 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.2  lukem  */
     25      1.1  lukem 
     26      1.1  lukem #include "portable.h"
     27      1.1  lukem 
     28      1.1  lukem #include <stdio.h>
     29      1.1  lukem 
     30      1.1  lukem #include <ac/string.h>
     31      1.1  lukem 
     32      1.1  lukem #include "slap.h"
     33      1.1  lukem #include "config.h"
     34      1.1  lukem #include "lutil.h"
     35      1.1  lukem 
     36      1.1  lukem /* Filter represents the memberURL of a group. */
     37      1.1  lukem typedef struct autogroup_filter_t {
     38      1.1  lukem 	struct berval			agf_dn;	/* The base DN in memberURL */
     39      1.1  lukem 	struct berval			agf_ndn;
     40      1.1  lukem 	struct berval			agf_filterstr;
     41      1.1  lukem 	Filter				*agf_filter;
     42      1.1  lukem 	int				agf_scope;
     43      1.1  lukem 	struct autogroup_filter_t	*agf_next;
     44      1.1  lukem } autogroup_filter_t;
     45      1.1  lukem 
     46      1.1  lukem /* Description of group attributes. */
     47      1.1  lukem typedef struct autogroup_def_t {
     48      1.1  lukem 	ObjectClass		*agd_oc;
     49      1.1  lukem 	AttributeDescription	*agd_member_url_ad;
     50      1.1  lukem 	AttributeDescription	*agd_member_ad;
     51      1.1  lukem 	struct autogroup_def_t	*agd_next;
     52      1.1  lukem } autogroup_def_t;
     53      1.1  lukem 
     54      1.1  lukem /* Represents the group entry. */
     55      1.1  lukem typedef struct autogroup_entry_t {
     56      1.1  lukem 	BerValue		age_dn;
     57      1.1  lukem 	BerValue		age_ndn;
     58      1.1  lukem 	autogroup_filter_t	*age_filter; /* List of filters made from memberURLs */
     59      1.1  lukem 	autogroup_def_t		*age_def; /* Attribute definition */
     60      1.1  lukem 	ldap_pvt_thread_mutex_t age_mutex;
     61      1.1  lukem 	struct autogroup_entry_t	*age_next;
     62      1.1  lukem } autogroup_entry_t;
     63      1.1  lukem 
     64      1.1  lukem /* Holds pointers to attribute definitions and groups. */
     65      1.1  lukem typedef struct autogroup_info_t {
     66      1.1  lukem 	autogroup_def_t		*agi_def;	/* Group attributes definitions. */
     67      1.1  lukem 	autogroup_entry_t	*agi_entry;	/* Group entries.  */
     68      1.1  lukem 	ldap_pvt_thread_mutex_t agi_mutex;
     69      1.1  lukem } autogroup_info_t;
     70      1.1  lukem 
     71      1.1  lukem /* Search callback for adding groups initially. */
     72      1.1  lukem typedef struct autogroup_sc_t {
     73      1.1  lukem 	autogroup_info_t		*ags_info;	/* Group definitions and entries.  */
     74      1.1  lukem 	autogroup_def_t		*ags_def;	/* Attributes definition of the group being added. */
     75      1.1  lukem } autogroup_sc_t;
     76      1.1  lukem 
     77      1.1  lukem /* Used for adding members, found when searching, to a group. */
     78      1.1  lukem typedef struct autogroup_ga_t {
     79      1.1  lukem 	autogroup_entry_t	*agg_group;	/* The group to which the members will be added. */
     80      1.1  lukem 	Entry			*agg_entry;	/* Used in autogroup_member_search_cb to modify
     81      1.1  lukem 						this entry with the search results. */
     82      1.1  lukem 
     83      1.1  lukem 	Modifications		*agg_mod;	/* Used in autogroup_member_search_modify_cb to hold the
     84      1.1  lukem 						search results which will be added to the group. */
     85      1.1  lukem 
     86      1.1  lukem 	Modifications		*agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
     87      1.1  lukem 						have to search for the last mod added. */
     88      1.1  lukem } autogroup_ga_t;
     89      1.1  lukem 
     90      1.1  lukem 
     91      1.1  lukem /*
     92      1.1  lukem **	dn, ndn	- the DN of the member to add
     93      1.1  lukem **	age	- the group to which the member DN will be added
     94      1.1  lukem */
     95      1.1  lukem static int
     96      1.1  lukem autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
     97      1.1  lukem {
     98      1.1  lukem 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
     99      1.1  lukem 	Modifications	modlist;
    100      1.1  lukem 	SlapReply	sreply = {REP_RESULT};
    101      1.1  lukem 	BerValue	vals[ 2 ], nvals[ 2 ];
    102      1.1  lukem 	slap_callback	cb = { NULL, slap_null_cb, NULL, NULL };
    103      1.1  lukem 	Operation	o = *op;
    104      1.1  lukem 
    105      1.1  lukem 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
    106      1.1  lukem 		dn->bv_val, age->age_dn.bv_val, 0);
    107      1.1  lukem 
    108      1.1  lukem 	assert( dn != NULL );
    109      1.1  lukem 	assert( ndn != NULL );
    110      1.1  lukem 
    111      1.1  lukem 	vals[ 0 ] = *dn;
    112      1.1  lukem 	BER_BVZERO( &vals[ 1 ] );
    113      1.1  lukem 	nvals[ 0 ] = *ndn;
    114      1.1  lukem 	BER_BVZERO( &nvals[ 1 ] );
    115      1.1  lukem 
    116      1.1  lukem 	modlist.sml_op = LDAP_MOD_ADD;
    117      1.1  lukem 	modlist.sml_desc = age->age_def->agd_member_ad;
    118      1.1  lukem 	modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
    119      1.1  lukem 	modlist.sml_values = vals;
    120      1.1  lukem 	modlist.sml_nvalues = nvals;
    121      1.1  lukem 	modlist.sml_numvals = 1;
    122      1.1  lukem 	modlist.sml_flags = SLAP_MOD_INTERNAL;
    123      1.1  lukem 	modlist.sml_next = NULL;
    124      1.1  lukem 
    125      1.1  lukem 	o.o_tag = LDAP_REQ_MODIFY;
    126      1.1  lukem 	o.o_callback = &cb;
    127      1.1  lukem 	o.orm_modlist = &modlist;
    128      1.1  lukem 	o.o_req_dn = age->age_dn;
    129      1.1  lukem 	o.o_req_ndn = age->age_ndn;
    130      1.1  lukem 	o.o_permissive_modify = 1;
    131      1.1  lukem 	o.o_managedsait = SLAP_CONTROL_CRITICAL;
    132      1.1  lukem 	o.o_relax = SLAP_CONTROL_CRITICAL;
    133      1.1  lukem 
    134      1.1  lukem 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    135      1.1  lukem 	(void)op->o_bd->be_modify( &o, &sreply );
    136      1.1  lukem 	o.o_bd->bd_info = (BackendInfo *)on;
    137      1.1  lukem 
    138      1.1  lukem 	return sreply.sr_err;
    139      1.1  lukem }
    140      1.1  lukem 
    141      1.1  lukem /*
    142      1.1  lukem ** dn,ndn	- the DN to be deleted
    143      1.1  lukem ** age		- the group from which the DN will be deleted
    144      1.1  lukem ** If we pass a NULL dn and ndn, all members are deleted from the group.
    145      1.1  lukem */
    146      1.1  lukem static int
    147      1.1  lukem autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
    148      1.1  lukem {
    149      1.1  lukem 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    150      1.1  lukem 	Modifications	modlist;
    151      1.1  lukem 	SlapReply	sreply = {REP_RESULT};
    152      1.1  lukem 	BerValue	vals[ 2 ], nvals[ 2 ];
    153      1.1  lukem 	slap_callback	cb = { NULL, slap_null_cb, NULL, NULL };
    154      1.1  lukem 	Operation	o = *op;
    155      1.1  lukem 
    156      1.1  lukem 	if ( dn == NULL || ndn == NULL ) {
    157      1.1  lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
    158      1.1  lukem 			age->age_dn.bv_val, 0 ,0);
    159      1.1  lukem 
    160      1.1  lukem 		modlist.sml_values = NULL;
    161      1.1  lukem 		modlist.sml_nvalues = NULL;
    162      1.1  lukem 		modlist.sml_numvals = 0;
    163      1.1  lukem 	} else {
    164      1.1  lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
    165      1.1  lukem 			dn->bv_val, age->age_dn.bv_val, 0);
    166      1.1  lukem 
    167      1.1  lukem 		vals[ 0 ] = *dn;
    168      1.1  lukem 		BER_BVZERO( &vals[ 1 ] );
    169      1.1  lukem 		nvals[ 0 ] = *ndn;
    170      1.1  lukem 		BER_BVZERO( &nvals[ 1 ] );
    171      1.1  lukem 
    172      1.1  lukem 		modlist.sml_values = vals;
    173      1.1  lukem 		modlist.sml_nvalues = nvals;
    174      1.1  lukem 		modlist.sml_numvals = 1;
    175      1.1  lukem 	}
    176      1.1  lukem 
    177      1.1  lukem 
    178      1.1  lukem 	modlist.sml_op = LDAP_MOD_DELETE;
    179      1.1  lukem 	modlist.sml_desc = age->age_def->agd_member_ad;
    180      1.1  lukem 	modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
    181      1.1  lukem 	modlist.sml_flags = SLAP_MOD_INTERNAL;
    182      1.1  lukem 	modlist.sml_next = NULL;
    183      1.1  lukem 
    184      1.1  lukem 	o.o_callback = &cb;
    185      1.1  lukem 	o.o_tag = LDAP_REQ_MODIFY;
    186      1.1  lukem 	o.orm_modlist = &modlist;
    187      1.1  lukem 	o.o_req_dn = age->age_dn;
    188      1.1  lukem 	o.o_req_ndn = age->age_ndn;
    189      1.1  lukem 	o.o_relax = SLAP_CONTROL_CRITICAL;
    190      1.1  lukem 	o.o_managedsait = SLAP_CONTROL_CRITICAL;
    191      1.1  lukem 	o.o_permissive_modify = 1;
    192      1.1  lukem 
    193      1.1  lukem 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    194      1.1  lukem 	(void)op->o_bd->be_modify( &o, &sreply );
    195      1.1  lukem 	o.o_bd->bd_info = (BackendInfo *)on;
    196      1.1  lukem 
    197      1.1  lukem 	return sreply.sr_err;
    198      1.1  lukem }
    199      1.1  lukem 
    200      1.1  lukem /*
    201      1.1  lukem ** Callback used to add entries to a group,
    202      1.1  lukem ** which are going to be written in the database
    203      1.1  lukem ** (used in bi_op_add)
    204      1.1  lukem ** The group is passed in autogroup_ga_t->agg_group
    205      1.1  lukem */
    206      1.1  lukem static int
    207      1.1  lukem autogroup_member_search_cb( Operation *op, SlapReply *rs )
    208      1.1  lukem {
    209      1.1  lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    210      1.1  lukem 
    211      1.1  lukem 	assert( op->o_tag == LDAP_REQ_SEARCH );
    212      1.1  lukem 
    213      1.1  lukem 	if ( rs->sr_type == REP_SEARCH ) {
    214      1.1  lukem 		autogroup_ga_t		*agg = (autogroup_ga_t *)op->o_callback->sc_private;
    215      1.1  lukem 		autogroup_entry_t	*age = agg->agg_group;
    216      1.1  lukem 		Modification		mod;
    217      1.1  lukem 		const char		*text = NULL;
    218      1.1  lukem 		char			textbuf[1024];
    219      1.1  lukem 		struct berval		vals[ 2 ], nvals[ 2 ];
    220      1.1  lukem 
    221      1.1  lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
    222      1.1  lukem 			rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
    223      1.1  lukem 
    224      1.1  lukem 		vals[ 0 ] = rs->sr_entry->e_name;
    225      1.1  lukem 		BER_BVZERO( &vals[ 1 ] );
    226      1.1  lukem 		nvals[ 0 ] = rs->sr_entry->e_nname;
    227      1.1  lukem 		BER_BVZERO( &nvals[ 1 ] );
    228      1.1  lukem 
    229      1.1  lukem 		mod.sm_op = LDAP_MOD_ADD;
    230      1.1  lukem 		mod.sm_desc = age->age_def->agd_member_ad;
    231      1.1  lukem 		mod.sm_type = age->age_def->agd_member_ad->ad_cname;
    232      1.1  lukem 		mod.sm_values = vals;
    233      1.1  lukem 		mod.sm_nvalues = nvals;
    234      1.1  lukem 		mod.sm_numvals = 1;
    235      1.1  lukem 
    236      1.1  lukem 		modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
    237      1.1  lukem 	}
    238      1.1  lukem 
    239      1.1  lukem 	return 0;
    240      1.1  lukem }
    241      1.1  lukem 
    242      1.1  lukem /*
    243      1.1  lukem ** Callback used to add entries to a group, which is already in the database.
    244      1.1  lukem ** (used in on_response)
    245      1.1  lukem ** The group is passed in autogroup_ga_t->agg_group
    246      1.1  lukem ** NOTE: Very slow.
    247      1.1  lukem */
    248      1.1  lukem static int
    249      1.1  lukem autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
    250      1.1  lukem {
    251      1.1  lukem 	assert( op->o_tag == LDAP_REQ_SEARCH );
    252      1.1  lukem 
    253      1.1  lukem 	if ( rs->sr_type == REP_SEARCH ) {
    254      1.1  lukem 		autogroup_ga_t		*agg = (autogroup_ga_t *)op->o_callback->sc_private;
    255      1.1  lukem 		autogroup_entry_t	*age = agg->agg_group;
    256      1.1  lukem 		Modifications		*modlist;
    257      1.1  lukem 		struct berval		vals[ 2 ], nvals[ 2 ];
    258      1.1  lukem 
    259      1.1  lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
    260      1.1  lukem 			rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
    261      1.1  lukem 
    262      1.1  lukem 		vals[ 0 ] = rs->sr_entry->e_name;
    263      1.1  lukem 		BER_BVZERO( &vals[ 1 ] );
    264      1.1  lukem 		nvals[ 0 ] = rs->sr_entry->e_nname;
    265      1.1  lukem 		BER_BVZERO( &nvals[ 1 ] );
    266      1.1  lukem 
    267      1.1  lukem 		modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
    268      1.1  lukem 
    269      1.1  lukem 		modlist->sml_op = LDAP_MOD_ADD;
    270      1.1  lukem 		modlist->sml_desc = age->age_def->agd_member_ad;
    271      1.1  lukem 		modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
    272      1.1  lukem 
    273      1.1  lukem 		ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
    274      1.1  lukem 		ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
    275      1.1  lukem 		modlist->sml_numvals = 1;
    276      1.1  lukem 
    277      1.1  lukem 		modlist->sml_flags = SLAP_MOD_INTERNAL;
    278      1.1  lukem 		modlist->sml_next = NULL;
    279      1.1  lukem 
    280      1.1  lukem 		if ( agg->agg_mod == NULL ) {
    281      1.1  lukem 			agg->agg_mod = modlist;
    282      1.1  lukem 			agg->agg_mod_last = modlist;
    283      1.1  lukem 		} else {
    284      1.1  lukem 			agg->agg_mod_last->sml_next = modlist;
    285      1.1  lukem 			agg->agg_mod_last = modlist;
    286      1.1  lukem 		}
    287      1.1  lukem 
    288      1.1  lukem 	}
    289      1.1  lukem 
    290      1.1  lukem 	return 0;
    291      1.1  lukem }
    292      1.1  lukem 
    293      1.1  lukem 
    294      1.1  lukem /*
    295      1.1  lukem ** Adds all entries matching the passed filter to the specified group.
    296      1.1  lukem ** If modify == 1, then we modify the group's entry in the database using be_modify.
    297      1.1  lukem ** If modify == 0, then, we must supply a rw entry for the group,
    298      1.1  lukem **	because we only modify the entry, without calling be_modify.
    299      1.1  lukem ** e	- the group entry, to which the members will be added
    300      1.1  lukem ** age	- the group
    301      1.1  lukem ** agf	- the filter
    302      1.1  lukem */
    303      1.1  lukem static int
    304      1.1  lukem autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
    305      1.1  lukem {
    306      1.1  lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    307      1.1  lukem 	Operation		o = *op;
    308      1.1  lukem 	SlapReply		rs = { REP_SEARCH };
    309      1.1  lukem 	slap_callback		cb = { 0 };
    310      1.1  lukem 	slap_callback		null_cb = { NULL, slap_null_cb, NULL, NULL };
    311      1.1  lukem 	autogroup_ga_t		agg;
    312      1.1  lukem 
    313      1.1  lukem 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
    314      1.1  lukem 		age->age_dn.bv_val, 0, 0);
    315      1.1  lukem 
    316      1.1  lukem 	o.ors_attrsonly = 0;
    317      1.1  lukem 	o.o_tag = LDAP_REQ_SEARCH;
    318      1.1  lukem 
    319      1.1  lukem 	o.o_req_dn = agf->agf_dn;
    320      1.1  lukem 	o.o_req_ndn = agf->agf_ndn;
    321      1.1  lukem 
    322      1.1  lukem 	o.ors_filterstr = agf->agf_filterstr;
    323      1.1  lukem 	o.ors_filter = agf->agf_filter;
    324      1.1  lukem 
    325      1.1  lukem 	o.ors_scope = agf->agf_scope;
    326      1.1  lukem 	o.ors_deref = LDAP_DEREF_NEVER;
    327      1.1  lukem 	o.ors_limit = NULL;
    328      1.1  lukem 	o.ors_tlimit = SLAP_NO_LIMIT;
    329      1.1  lukem 	o.ors_slimit = SLAP_NO_LIMIT;
    330      1.1  lukem 	o.ors_attrs =  slap_anlist_no_attrs;
    331      1.1  lukem 
    332      1.1  lukem 	agg.agg_group = age;
    333      1.1  lukem 	agg.agg_mod = NULL;
    334      1.1  lukem 	agg.agg_mod_last = NULL;
    335      1.1  lukem 	agg.agg_entry = e;
    336      1.1  lukem 	cb.sc_private = &agg;
    337      1.1  lukem 
    338      1.1  lukem 	if ( modify == 1 ) {
    339      1.1  lukem 		cb.sc_response = autogroup_member_search_modify_cb;
    340      1.1  lukem 	} else {
    341      1.1  lukem 		cb.sc_response = autogroup_member_search_cb;
    342      1.1  lukem 	}
    343      1.1  lukem 
    344      1.1  lukem 	cb.sc_cleanup = NULL;
    345      1.1  lukem 	cb.sc_next = NULL;
    346      1.1  lukem 
    347      1.1  lukem 	o.o_callback = &cb;
    348      1.1  lukem 
    349      1.1  lukem 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    350      1.1  lukem 	op->o_bd->be_search( &o, &rs );
    351      1.1  lukem 	o.o_bd->bd_info = (BackendInfo *)on;
    352      1.1  lukem 
    353      1.1  lukem 	if ( modify == 1 ) {
    354      1.1  lukem 		o = *op;
    355      1.1  lukem 		o.o_callback = &null_cb;
    356      1.1  lukem 		o.o_tag = LDAP_REQ_MODIFY;
    357      1.1  lukem 		o.orm_modlist = agg.agg_mod;
    358      1.1  lukem 		o.o_req_dn = age->age_dn;
    359      1.1  lukem 		o.o_req_ndn = age->age_ndn;
    360      1.1  lukem 		o.o_relax = SLAP_CONTROL_CRITICAL;
    361      1.1  lukem 		o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
    362      1.1  lukem 		o.o_permissive_modify = 1;
    363      1.1  lukem 
    364      1.1  lukem 		o.o_bd->bd_info = (BackendInfo *)on->on_info;
    365      1.1  lukem 		(void)op->o_bd->be_modify( &o, &rs );
    366      1.1  lukem 		o.o_bd->bd_info = (BackendInfo *)on;
    367      1.1  lukem 
    368      1.1  lukem 		slap_mods_free(agg.agg_mod, 1);
    369      1.1  lukem 	}
    370      1.1  lukem 
    371      1.1  lukem 	return 0;
    372      1.1  lukem }
    373      1.1  lukem 
    374      1.1  lukem /*
    375      1.1  lukem ** Adds a group to the internal list from the passed entry.
    376      1.1  lukem ** scan specifies whether to add all maching members to the group.
    377      1.1  lukem ** modify specifies whether to modify the given group entry (when modify == 0),
    378      1.1  lukem **	or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
    379      1.1  lukem ** agi	- pointer to the groups and the attribute definitions
    380      1.1  lukem ** agd - the attribute definition of the added group
    381      1.1  lukem ** e	- the entry representing the group, can be NULL if the ndn is specified, and modify == 1
    382      1.1  lukem ** ndn	- the DN of the group, can be NULL if we give a non-NULL e
    383      1.1  lukem */
    384      1.1  lukem static int
    385      1.1  lukem autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
    386      1.1  lukem {
    387      1.1  lukem 	autogroup_entry_t	**agep = &agi->agi_entry;
    388      1.1  lukem 	autogroup_filter_t	*agf, *agf_prev = NULL;
    389      1.1  lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    390      1.1  lukem 	LDAPURLDesc		*lud = NULL;
    391      1.1  lukem 	Attribute		*a;
    392      1.1  lukem 	BerValue		*bv, dn;
    393      1.1  lukem 	int			rc = 0, match = 1, null_entry = 0;
    394      1.1  lukem 
    395      1.1  lukem 	if ( e == NULL ) {
    396      1.1  lukem 		if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
    397      1.1  lukem 			LDAP_SUCCESS || e == NULL ) {
    398      1.1  lukem 			Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
    399      1.1  lukem 			return 1;
    400      1.1  lukem 		}
    401      1.1  lukem 
    402      1.1  lukem 		null_entry = 1;
    403      1.1  lukem 	}
    404      1.1  lukem 
    405      1.1  lukem 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
    406      1.1  lukem 		e->e_name.bv_val, 0, 0);
    407      1.1  lukem 
    408      1.1  lukem 	if ( agi->agi_entry != NULL ) {
    409      1.1  lukem 		for ( ; *agep ; agep = &(*agep)->age_next ) {
    410      1.1  lukem 			dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
    411      1.1  lukem 			if ( match == 0 ) {
    412      1.1  lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
    413      1.1  lukem 				return 1;
    414      1.1  lukem 			}
    415      1.1  lukem 			/* goto last */;
    416      1.1  lukem 		}
    417      1.1  lukem 	}
    418      1.1  lukem 
    419      1.1  lukem 
    420      1.1  lukem 	*agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
    421      1.1  lukem 	ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
    422      1.1  lukem 	(*agep)->age_def = agd;
    423      1.1  lukem 	(*agep)->age_filter = NULL;
    424      1.1  lukem 
    425      1.1  lukem 	ber_dupbv( &(*agep)->age_dn, &e->e_name );
    426      1.1  lukem 	ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
    427      1.1  lukem 
    428      1.1  lukem 	a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
    429      1.1  lukem 
    430      1.1  lukem 	if ( null_entry == 1 ) {
    431      1.1  lukem 		a = attrs_dup( a );
    432      1.1  lukem 		overlay_entry_release_ov( op, e, 0, on );
    433      1.1  lukem 	}
    434      1.1  lukem 
    435      1.1  lukem 	if( a == NULL ) {
    436      1.1  lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
    437      1.1  lukem 	} else {
    438      1.1  lukem 		for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
    439      1.1  lukem 
    440      1.1  lukem 			agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
    441      1.1  lukem 
    442      1.1  lukem 			if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
    443      1.1  lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
    444      1.1  lukem 				/* FIXME: error? */
    445      1.1  lukem 				ch_free( agf );
    446      1.1  lukem 				continue;
    447      1.1  lukem 			}
    448      1.1  lukem 
    449      1.1  lukem 			agf->agf_scope = lud->lud_scope;
    450      1.1  lukem 
    451      1.1  lukem 			if ( lud->lud_dn == NULL ) {
    452      1.1  lukem 				BER_BVSTR( &dn, "" );
    453      1.1  lukem 			} else {
    454      1.1  lukem 				ber_str2bv( lud->lud_dn, 0, 0, &dn );
    455      1.1  lukem 			}
    456      1.1  lukem 
    457      1.1  lukem 			rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
    458      1.1  lukem 			if ( rc != LDAP_SUCCESS ) {
    459      1.1  lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
    460      1.1  lukem 				/* FIXME: error? */
    461      1.1  lukem 				goto cleanup;
    462      1.1  lukem 			}
    463      1.1  lukem 
    464      1.1  lukem 			if ( lud->lud_filter != NULL ) {
    465      1.1  lukem 				ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
    466      1.1  lukem 				agf->agf_filter = str2filter( lud->lud_filter );
    467      1.1  lukem 			}
    468      1.1  lukem 
    469      1.1  lukem 			agf->agf_next = NULL;
    470      1.1  lukem 
    471      1.1  lukem 
    472      1.1  lukem 			if( (*agep)->age_filter == NULL ) {
    473      1.1  lukem 				(*agep)->age_filter = agf;
    474      1.1  lukem 			}
    475      1.1  lukem 
    476      1.1  lukem 			if( agf_prev != NULL ) {
    477      1.1  lukem 				agf_prev->agf_next = agf;
    478      1.1  lukem 			}
    479      1.1  lukem 
    480      1.1  lukem 			agf_prev = agf;
    481      1.1  lukem 
    482      1.1  lukem 			if ( scan == 1 ){
    483      1.1  lukem 				autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
    484      1.1  lukem 			}
    485      1.1  lukem 
    486      1.1  lukem 			Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
    487      1.1  lukem 				agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
    488      1.1  lukem 
    489      1.1  lukem 			ldap_free_urldesc( lud );
    490      1.1  lukem 
    491      1.1  lukem 			continue;
    492      1.1  lukem 
    493      1.1  lukem 
    494      1.1  lukem cleanup:;
    495      1.1  lukem 
    496      1.1  lukem 			ldap_free_urldesc( lud );
    497      1.1  lukem 			ch_free( agf );
    498      1.1  lukem 		}
    499      1.1  lukem 	}
    500      1.1  lukem 
    501      1.1  lukem 	if ( null_entry == 1 ) {
    502      1.1  lukem 		attrs_free( a );
    503      1.1  lukem 	}
    504      1.1  lukem 	return rc;
    505      1.1  lukem }
    506      1.1  lukem 
    507      1.1  lukem /*
    508      1.1  lukem ** Used when opening the database to add all existing
    509      1.1  lukem ** groups from the database to our internal list.
    510      1.1  lukem */
    511      1.1  lukem static int
    512      1.1  lukem autogroup_group_add_cb( Operation *op, SlapReply *rs )
    513      1.1  lukem {
    514      1.1  lukem 	assert( op->o_tag == LDAP_REQ_SEARCH );
    515      1.1  lukem 
    516      1.1  lukem 	if ( rs->sr_type == REP_SEARCH ) {
    517      1.1  lukem 		autogroup_sc_t		*ags = (autogroup_sc_t *)op->o_callback->sc_private;
    518      1.1  lukem 
    519      1.1  lukem 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
    520      1.1  lukem 			rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
    521      1.1  lukem 
    522      1.1  lukem 		autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
    523      1.1  lukem 	}
    524      1.1  lukem 
    525      1.1  lukem 	return 0;
    526      1.1  lukem }
    527      1.1  lukem 
    528      1.1  lukem 
    529      1.1  lukem /*
    530      1.1  lukem ** When adding a group, we first strip any existing members,
    531      1.1  lukem ** and add all which match the filters ourselfs.
    532      1.1  lukem */
    533      1.1  lukem static int
    534      1.1  lukem autogroup_add_entry( Operation *op, SlapReply *rs)
    535      1.1  lukem {
    536      1.1  lukem 		slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    537      1.1  lukem 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
    538      1.1  lukem 	autogroup_def_t		*agd = agi->agi_def;
    539      1.1  lukem 	autogroup_entry_t	*age = agi->agi_entry;
    540      1.1  lukem 	autogroup_filter_t	*agf;
    541      1.1  lukem 	int			rc = 0;
    542      1.1  lukem 
    543      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
    544      1.1  lukem 		op->ora_e->e_name.bv_val, 0, 0);
    545      1.1  lukem 
    546      1.1  lukem 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
    547      1.1  lukem 
    548      1.1  lukem 	/* Check if it's a group. */
    549      1.1  lukem 	for ( ; agd ; agd = agd->agd_next ) {
    550      1.1  lukem 		if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
    551      1.1  lukem 			Modification		mod;
    552      1.1  lukem 			const char		*text = NULL;
    553      1.1  lukem 			char			textbuf[1024];
    554      1.1  lukem 
    555      1.1  lukem 			mod.sm_op = LDAP_MOD_DELETE;
    556      1.1  lukem 			mod.sm_desc = agd->agd_member_ad;
    557      1.1  lukem 			mod.sm_type = agd->agd_member_ad->ad_cname;
    558      1.1  lukem 			mod.sm_values = NULL;
    559      1.1  lukem 			mod.sm_nvalues = NULL;
    560      1.1  lukem 
    561      1.1  lukem 			/* We don't want any member attributes added by the user. */
    562      1.1  lukem 			modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
    563      1.1  lukem 
    564      1.1  lukem 			autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
    565      1.1  lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    566      1.1  lukem 			return SLAP_CB_CONTINUE;
    567      1.1  lukem 		}
    568      1.1  lukem 	}
    569      1.1  lukem 
    570      1.1  lukem 	for ( ; age ; age = age->age_next ) {
    571      1.1  lukem 		ldap_pvt_thread_mutex_lock( &age->age_mutex );
    572      1.1  lukem 
    573      1.1  lukem 		/* Check if any of the filters are the suffix to the entry DN.
    574      1.1  lukem 		   If yes, we can test that filter against the entry. */
    575      1.1  lukem 
    576      1.1  lukem 		for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
    577      1.1  lukem 			if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
    578      1.1  lukem 				rc = test_filter( op, op->ora_e, agf->agf_filter );
    579      1.1  lukem 				if ( rc == LDAP_COMPARE_TRUE ) {
    580      1.1  lukem 				autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
    581      1.1  lukem 					break;
    582      1.1  lukem 				}
    583      1.1  lukem 			}
    584      1.1  lukem 		}
    585      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    586      1.1  lukem 	}
    587      1.1  lukem 
    588      1.1  lukem 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    589      1.1  lukem 
    590      1.1  lukem 	return SLAP_CB_CONTINUE;
    591      1.1  lukem }
    592      1.1  lukem 
    593      1.1  lukem /*
    594      1.1  lukem ** agi	- internal group and attribute definitions list
    595      1.1  lukem ** e	- the group to remove from the internal list
    596      1.1  lukem */
    597      1.1  lukem static int
    598      1.1  lukem autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
    599      1.1  lukem {
    600      1.1  lukem 	autogroup_entry_t	*age = agi->agi_entry,
    601      1.1  lukem 				*age_prev = NULL,
    602      1.1  lukem 				*age_next;
    603      1.1  lukem 	int			rc = 1;
    604      1.1  lukem 
    605      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
    606      1.1  lukem 		age->age_dn.bv_val, 0, 0);
    607      1.1  lukem 
    608      1.1  lukem 	for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
    609      1.1  lukem 		age_next = age->age_next;
    610      1.1  lukem 
    611      1.1  lukem 		if ( age == e ) {
    612      1.1  lukem 			autogroup_filter_t	*agf = age->age_filter,
    613      1.1  lukem 							*agf_next;
    614      1.1  lukem 
    615      1.1  lukem 			if ( age_prev != NULL ) {
    616      1.1  lukem 				age_prev->age_next = age_next;
    617      1.1  lukem 			} else {
    618      1.1  lukem 				agi->agi_entry = NULL;
    619      1.1  lukem 			}
    620      1.1  lukem 
    621      1.1  lukem 			ch_free( age->age_dn.bv_val );
    622      1.1  lukem 			ch_free( age->age_ndn.bv_val );
    623      1.1  lukem 
    624      1.1  lukem 			for( agf_next = agf ; agf_next ; agf = agf_next ){
    625      1.1  lukem 				agf_next = agf->agf_next;
    626      1.1  lukem 
    627      1.1  lukem 				filter_free( agf->agf_filter );
    628      1.1  lukem 				ch_free( agf->agf_filterstr.bv_val );
    629      1.1  lukem 				ch_free( agf->agf_dn.bv_val );
    630      1.1  lukem 				ch_free( agf->agf_ndn.bv_val );
    631      1.1  lukem 			}
    632      1.1  lukem 
    633      1.1  lukem 			ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    634      1.1  lukem 			ldap_pvt_thread_mutex_destroy( &age->age_mutex );
    635      1.1  lukem 			ch_free( age );
    636      1.1  lukem 
    637      1.1  lukem 			rc = 0;
    638      1.1  lukem 			return rc;
    639      1.1  lukem 
    640      1.1  lukem 		}
    641      1.1  lukem 	}
    642      1.1  lukem 
    643      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);
    644      1.1  lukem 
    645      1.1  lukem 	return rc;
    646      1.1  lukem 
    647      1.1  lukem }
    648      1.1  lukem 
    649      1.1  lukem static int
    650      1.1  lukem autogroup_delete_entry( Operation *op, SlapReply *rs)
    651      1.1  lukem {
    652      1.1  lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    653      1.1  lukem 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
    654      1.1  lukem 	autogroup_entry_t	*age = agi->agi_entry,
    655      1.1  lukem 				*age_prev, *age_next;
    656      1.1  lukem 	autogroup_filter_t	*agf;
    657      1.1  lukem 	Entry			*e;
    658      1.1  lukem 	int			matched_group = 0, rc = 0;
    659      1.1  lukem 
    660      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
    661      1.1  lukem 
    662      1.1  lukem 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
    663      1.1  lukem 
    664      1.1  lukem 	if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
    665      1.1  lukem 		LDAP_SUCCESS || e == NULL ) {
    666      1.1  lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
    667      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    668      1.1  lukem 		return SLAP_CB_CONTINUE;
    669      1.1  lukem 	}
    670      1.1  lukem 
    671      1.1  lukem 	/* Check if the entry to be deleted is one of our groups. */
    672      1.1  lukem 	for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
    673      1.1  lukem 		ldap_pvt_thread_mutex_lock( &age->age_mutex );
    674      1.1  lukem 		age_next = age->age_next;
    675      1.1  lukem 
    676      1.1  lukem 		if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
    677      1.1  lukem 			int match = 1;
    678      1.1  lukem 
    679      1.1  lukem 			matched_group = 1;
    680      1.1  lukem 
    681      1.1  lukem 			dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
    682      1.1  lukem 
    683      1.1  lukem 			if ( match == 0 ) {
    684      1.1  lukem 				autogroup_delete_group( agi, age );
    685      1.1  lukem 				break;
    686      1.1  lukem 			}
    687      1.1  lukem 		}
    688      1.1  lukem 
    689      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    690      1.1  lukem 	}
    691      1.1  lukem 
    692      1.1  lukem 	if ( matched_group == 1 ) {
    693      1.1  lukem 		overlay_entry_release_ov( op, e, 0, on );
    694      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    695      1.1  lukem 		return SLAP_CB_CONTINUE;
    696      1.1  lukem 	}
    697      1.1  lukem 
    698      1.1  lukem 	/* Check if the entry matches any of the groups.
    699      1.1  lukem 	   If yes, we can delete the entry from that group. */
    700      1.1  lukem 
    701      1.1  lukem 	for ( age = agi->agi_entry ; age ; age = age->age_next ) {
    702      1.1  lukem 		ldap_pvt_thread_mutex_lock( &age->age_mutex );
    703      1.1  lukem 
    704      1.1  lukem 		for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
    705      1.1  lukem 			if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
    706      1.1  lukem 				rc = test_filter( op, e, agf->agf_filter );
    707      1.1  lukem 				if ( rc == LDAP_COMPARE_TRUE ) {
    708      1.1  lukem 				autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
    709      1.1  lukem 					break;
    710      1.1  lukem 				}
    711      1.1  lukem 			}
    712      1.1  lukem 		}
    713      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    714      1.1  lukem 	}
    715      1.1  lukem 
    716      1.1  lukem 	overlay_entry_release_ov( op, e, 0, on );
    717      1.1  lukem 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    718      1.1  lukem 
    719      1.1  lukem 	return SLAP_CB_CONTINUE;
    720      1.1  lukem }
    721      1.1  lukem 
    722      1.1  lukem static int
    723      1.1  lukem autogroup_response( Operation *op, SlapReply *rs )
    724      1.1  lukem {
    725      1.1  lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    726      1.1  lukem 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
    727      1.1  lukem 	autogroup_def_t		*agd = agi->agi_def;
    728      1.1  lukem 	autogroup_entry_t	*age = agi->agi_entry;
    729      1.1  lukem 	autogroup_filter_t	*agf;
    730      1.1  lukem 	BerValue		new_dn, new_ndn, pdn;
    731      1.1  lukem 	Entry			*e, *group;
    732      1.1  lukem 	Attribute		*a;
    733      1.1  lukem 	int			is_olddn, is_newdn, dn_equal;
    734      1.1  lukem 
    735      1.1  lukem 	if ( op->o_tag == LDAP_REQ_MODRDN ) {
    736      1.1  lukem 		if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
    737      1.1  lukem 
    738      1.1  lukem 			Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
    739      1.1  lukem 
    740      1.1  lukem 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
    741      1.1  lukem 
    742      1.1  lukem 			if ( op->oq_modrdn.rs_newSup ) {
    743      1.1  lukem 				pdn = *op->oq_modrdn.rs_newSup;
    744      1.1  lukem 			} else {
    745      1.1  lukem 				dnParent( &op->o_req_dn, &pdn );
    746      1.1  lukem 			}
    747      1.1  lukem 			build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
    748      1.1  lukem 
    749      1.1  lukem 			if ( op->oq_modrdn.rs_nnewSup ) {
    750      1.1  lukem 				pdn = *op->oq_modrdn.rs_nnewSup;
    751      1.1  lukem 			} else {
    752      1.1  lukem 				dnParent( &op->o_req_ndn, &pdn );
    753      1.1  lukem 			}
    754      1.1  lukem 			build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
    755      1.1  lukem 
    756      1.1  lukem 			Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
    757      1.1  lukem 
    758      1.1  lukem 			dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
    759      1.1  lukem 
    760      1.1  lukem 			if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
    761      1.1  lukem 				LDAP_SUCCESS || e == NULL ) {
    762      1.1  lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
    763      1.1  lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    764      1.1  lukem 				return SLAP_CB_CONTINUE;
    765      1.1  lukem 			}
    766      1.1  lukem 
    767      1.1  lukem 			a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
    768      1.1  lukem 
    769      1.1  lukem 
    770      1.1  lukem 			if ( a == NULL ) {
    771      1.1  lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
    772      1.1  lukem 				overlay_entry_release_ov( op, e, 0, on );
    773      1.1  lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    774      1.1  lukem 				return SLAP_CB_CONTINUE;
    775      1.1  lukem 			}
    776      1.1  lukem 
    777      1.1  lukem 
    778      1.1  lukem 			/* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
    779      1.1  lukem 			for ( ; agd; agd = agd->agd_next ) {
    780      1.1  lukem 
    781      1.1  lukem 				if ( value_find_ex( slap_schema.si_ad_objectClass,
    782      1.1  lukem 						SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
    783      1.1  lukem 						SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
    784      1.1  lukem 						a->a_nvals, &agd->agd_oc->soc_cname,
    785      1.1  lukem 						op->o_tmpmemctx ) == 0 )
    786      1.1  lukem 				{
    787      1.1  lukem 					for ( age = agi->agi_entry ; age ; age = age->age_next ) {
    788      1.1  lukem 						int match = 1;
    789      1.1  lukem 
    790      1.1  lukem 						dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
    791      1.1  lukem 						if ( match == 0 ) {
    792      1.1  lukem 							Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
    793      1.1  lukem 							ber_dupbv( &age->age_dn, &new_dn );
    794      1.1  lukem 							ber_dupbv( &age->age_ndn, &new_ndn );
    795      1.1  lukem 
    796      1.1  lukem 							op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx  );
    797      1.1  lukem 							op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
    798      1.1  lukem 							overlay_entry_release_ov( op, e, 0, on );
    799      1.1  lukem 							ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    800      1.1  lukem 							return SLAP_CB_CONTINUE;
    801      1.1  lukem 						}
    802      1.1  lukem 					}
    803      1.1  lukem 
    804      1.1  lukem 				}
    805      1.1  lukem 			}
    806      1.1  lukem 
    807      1.1  lukem 			overlay_entry_release_ov( op, e, 0, on );
    808      1.1  lukem 
    809      1.1  lukem 			/* For each group:
    810      1.1  lukem 			   1. check if the orginal entry's DN is in the group.
    811      1.1  lukem 			   2. chceck if the any of the group filter's base DN is a suffix of the new DN
    812      1.1  lukem 
    813      1.1  lukem 			   If 1 and 2 are both false, we do nothing.
    814      1.1  lukem 			   If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
    815      1.1  lukem 			   If 1 is false, and 2 is true, we check the entry against the group's filters,
    816      1.1  lukem 				and add it's DN to the group.
    817      1.1  lukem 			   If 1 is true, and 2 is false, we delete the entry's DN from the group.
    818      1.1  lukem 			*/
    819      1.1  lukem 			for ( age = agi->agi_entry ; age ; age = age->age_next ) {
    820      1.1  lukem 				is_olddn = 0;
    821      1.1  lukem 				is_newdn = 0;
    822      1.1  lukem 
    823      1.1  lukem 
    824      1.1  lukem 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
    825      1.1  lukem 
    826      1.1  lukem 				if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
    827      1.1  lukem 					LDAP_SUCCESS || group == NULL ) {
    828      1.1  lukem 					Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
    829      1.1  lukem 
    830      1.1  lukem 					op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
    831      1.1  lukem 					op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
    832      1.1  lukem 
    833      1.1  lukem 					ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    834      1.1  lukem 					ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    835      1.1  lukem 					return SLAP_CB_CONTINUE;
    836      1.1  lukem 				}
    837      1.1  lukem 
    838      1.1  lukem 				a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
    839      1.1  lukem 
    840      1.1  lukem 				if ( a != NULL ) {
    841      1.1  lukem 					if ( value_find_ex( age->age_def->agd_member_ad,
    842      1.1  lukem 							SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
    843      1.1  lukem 							SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
    844      1.1  lukem 							a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
    845      1.1  lukem 					{
    846      1.1  lukem 						is_olddn = 1;
    847      1.1  lukem 					}
    848      1.1  lukem 
    849      1.1  lukem 				}
    850      1.1  lukem 
    851      1.1  lukem 				overlay_entry_release_ov( op, group, 0, on );
    852      1.1  lukem 
    853      1.1  lukem 				for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
    854      1.1  lukem 					if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
    855      1.1  lukem 						is_newdn = 1;
    856      1.1  lukem 						break;
    857      1.1  lukem 					}
    858      1.1  lukem 				}
    859      1.1  lukem 
    860      1.1  lukem 
    861      1.1  lukem 				if ( is_olddn == 1 && is_newdn == 0 ) {
    862      1.1  lukem 					autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
    863      1.1  lukem 				} else
    864      1.1  lukem 				if ( is_olddn == 0 && is_newdn == 1 ) {
    865      1.1  lukem 					for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
    866      1.1  lukem 						if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
    867      1.1  lukem 							autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
    868      1.1  lukem 							break;
    869      1.1  lukem 						}
    870      1.1  lukem 					}
    871      1.1  lukem 				} else
    872      1.1  lukem 				if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
    873      1.1  lukem 					autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
    874      1.1  lukem 					autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
    875      1.1  lukem 				}
    876      1.1  lukem 
    877      1.1  lukem 				ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    878      1.1  lukem 			}
    879      1.1  lukem 
    880      1.1  lukem 			op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
    881      1.1  lukem 			op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
    882      1.1  lukem 
    883      1.1  lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    884      1.1  lukem 		}
    885      1.1  lukem 	}
    886      1.1  lukem 
    887      1.1  lukem 	if ( op->o_tag == LDAP_REQ_MODIFY ) {
    888      1.1  lukem 		if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS  && !get_manageDSAit( op ) ) {
    889      1.1  lukem 			Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
    890      1.1  lukem 
    891      1.1  lukem 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
    892      1.1  lukem 
    893      1.1  lukem 			if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
    894      1.1  lukem 				LDAP_SUCCESS || e == NULL ) {
    895      1.1  lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
    896      1.1  lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    897      1.1  lukem 				return SLAP_CB_CONTINUE;
    898      1.1  lukem 			}
    899      1.1  lukem 
    900      1.1  lukem 			a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
    901      1.1  lukem 
    902      1.1  lukem 
    903      1.1  lukem 			if ( a == NULL ) {
    904      1.1  lukem 				Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
    905      1.1  lukem 				overlay_entry_release_ov( op, e, 0, on );
    906      1.1  lukem 				ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    907      1.1  lukem 				return SLAP_CB_CONTINUE;
    908      1.1  lukem 			}
    909      1.1  lukem 
    910      1.1  lukem 
    911      1.1  lukem 			/* If we modify a group's memberURL, we have to delete all of it's members,
    912      1.1  lukem 			   and add them anew, because we cannot tell from which memberURL a member was added. */
    913      1.1  lukem 			for ( ; agd; agd = agd->agd_next ) {
    914      1.1  lukem 
    915      1.1  lukem 				if ( value_find_ex( slap_schema.si_ad_objectClass,
    916      1.1  lukem 						SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
    917      1.1  lukem 						SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
    918      1.1  lukem 						a->a_nvals, &agd->agd_oc->soc_cname,
    919      1.1  lukem 						op->o_tmpmemctx ) == 0 )
    920      1.1  lukem 				{
    921      1.1  lukem 					Modifications	*m;
    922      1.1  lukem 					int		match = 1;
    923      1.1  lukem 
    924      1.1  lukem 					m = op->orm_modlist;
    925      1.1  lukem 
    926      1.1  lukem 					for ( ; age ; age = age->age_next ) {
    927      1.1  lukem 						ldap_pvt_thread_mutex_lock( &age->age_mutex );
    928      1.1  lukem 
    929      1.1  lukem 						dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
    930      1.1  lukem 
    931      1.1  lukem 						if ( match == 0 ) {
    932      1.1  lukem 							for ( ; m ; m = m->sml_next ) {
    933      1.1  lukem 								if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
    934      1.1  lukem 									autogroup_def_t	*group_agd = age->age_def;
    935      1.1  lukem 									Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
    936      1.1  lukem 										op->o_req_dn.bv_val, 0, 0);
    937      1.1  lukem 
    938      1.1  lukem 									overlay_entry_release_ov( op, e, 0, on );
    939      1.1  lukem 
    940      1.1  lukem 									autogroup_delete_member_from_group( op, NULL, NULL, age );
    941      1.1  lukem 									autogroup_delete_group( agi, age );
    942      1.1  lukem 
    943      1.1  lukem 									autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
    944      1.1  lukem 
    945      1.1  lukem 									ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    946      1.1  lukem 									return SLAP_CB_CONTINUE;
    947      1.1  lukem 								}
    948      1.1  lukem 							}
    949      1.1  lukem 
    950      1.1  lukem 							ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    951      1.1  lukem 							break;
    952      1.1  lukem 						}
    953      1.1  lukem 
    954      1.1  lukem 						ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    955      1.1  lukem 					}
    956      1.1  lukem 
    957      1.1  lukem 					overlay_entry_release_ov( op, e, 0, on );
    958      1.1  lukem 					ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    959      1.1  lukem 					return SLAP_CB_CONTINUE;
    960      1.1  lukem 				}
    961      1.1  lukem 			}
    962      1.1  lukem 
    963      1.1  lukem 			overlay_entry_release_ov( op, e, 0, on );
    964      1.1  lukem 
    965      1.1  lukem 			/* When modifing any of the attributes of an entry, we must
    966      1.1  lukem 			   check if the entry is in any of our groups, and if
    967      1.1  lukem 			   the modified entry maches any of the filters of that group.
    968      1.1  lukem 
    969      1.1  lukem 			   If the entry exists in a group, but the modified attributes do
    970      1.1  lukem 				not match any of the group's filters, we delete the entry from that group.
    971      1.1  lukem 			   If the entry doesn't exist in a group, but matches a filter,
    972      1.1  lukem 				we add it to that group.
    973      1.1  lukem 			*/
    974      1.1  lukem 			for ( age = agi->agi_entry ; age ; age = age->age_next ) {
    975      1.1  lukem 				is_olddn = 0;
    976      1.1  lukem 				is_newdn = 0;
    977      1.1  lukem 
    978      1.1  lukem 
    979      1.1  lukem 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
    980      1.1  lukem 
    981      1.1  lukem 				if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
    982      1.1  lukem 					LDAP_SUCCESS || group == NULL ) {
    983      1.1  lukem 					Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
    984      1.1  lukem 						age->age_dn.bv_val, 0, 0);
    985      1.1  lukem 
    986      1.1  lukem 					ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    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 				a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
    992      1.1  lukem 
    993      1.1  lukem 				if ( a != NULL ) {
    994      1.1  lukem 					if ( value_find_ex( age->age_def->agd_member_ad,
    995      1.1  lukem 							SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
    996      1.1  lukem 							SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
    997      1.1  lukem 							a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
    998      1.1  lukem 					{
    999      1.1  lukem 						is_olddn = 1;
   1000      1.1  lukem 					}
   1001      1.1  lukem 
   1002      1.1  lukem 				}
   1003      1.1  lukem 
   1004      1.1  lukem 				overlay_entry_release_ov( op, group, 0, on );
   1005      1.1  lukem 
   1006      1.1  lukem 				for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1007      1.1  lukem 					if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
   1008      1.1  lukem 						if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
   1009      1.1  lukem 							is_newdn = 1;
   1010      1.1  lukem 							break;
   1011      1.1  lukem 						}
   1012      1.1  lukem 					}
   1013      1.1  lukem 				}
   1014      1.1  lukem 
   1015      1.1  lukem 				if ( is_olddn == 1 && is_newdn == 0 ) {
   1016      1.1  lukem 					autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
   1017      1.1  lukem 				} else
   1018      1.1  lukem 				if ( is_olddn == 0 && is_newdn == 1 ) {
   1019      1.1  lukem 					autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
   1020      1.1  lukem 				}
   1021      1.1  lukem 
   1022      1.1  lukem 				ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1023      1.1  lukem 			}
   1024      1.1  lukem 
   1025      1.1  lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1026      1.1  lukem 		}
   1027      1.1  lukem 	}
   1028      1.1  lukem 
   1029      1.1  lukem 	return SLAP_CB_CONTINUE;
   1030      1.1  lukem }
   1031      1.1  lukem 
   1032      1.1  lukem /*
   1033      1.1  lukem ** When modifing a group, we must deny any modifications to the member attribute,
   1034      1.1  lukem ** because the group would be inconsistent.
   1035      1.1  lukem */
   1036      1.1  lukem static int
   1037      1.1  lukem autogroup_modify_entry( Operation *op, SlapReply *rs)
   1038      1.1  lukem {
   1039      1.1  lukem 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
   1040      1.1  lukem 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
   1041      1.1  lukem 	autogroup_def_t		*agd = agi->agi_def;
   1042      1.1  lukem 	autogroup_entry_t	*age = agi->agi_entry;
   1043      1.1  lukem 	Entry			*e;
   1044      1.1  lukem 	Attribute		*a;
   1045      1.1  lukem 
   1046      1.1  lukem 	if ( get_manageDSAit( op ) ) {
   1047      1.1  lukem 		return SLAP_CB_CONTINUE;
   1048      1.1  lukem 	}
   1049      1.1  lukem 
   1050      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1051      1.1  lukem 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1052      1.1  lukem 
   1053      1.1  lukem 	if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
   1054      1.1  lukem 		LDAP_SUCCESS || e == NULL ) {
   1055      1.1  lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1056      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1057      1.1  lukem 		return SLAP_CB_CONTINUE;
   1058      1.1  lukem 	}
   1059      1.1  lukem 
   1060      1.1  lukem 	a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
   1061      1.1  lukem 
   1062      1.1  lukem 	if ( a == NULL ) {
   1063      1.1  lukem 		Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
   1064      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1065      1.1  lukem 		return SLAP_CB_CONTINUE;
   1066      1.1  lukem 	}
   1067      1.1  lukem 
   1068      1.1  lukem 
   1069      1.1  lukem 	for ( ; agd; agd = agd->agd_next ) {
   1070      1.1  lukem 
   1071      1.1  lukem 		if ( value_find_ex( slap_schema.si_ad_objectClass,
   1072      1.1  lukem 				SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   1073      1.1  lukem 				SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
   1074      1.1  lukem 				a->a_nvals, &agd->agd_oc->soc_cname,
   1075      1.1  lukem 				op->o_tmpmemctx ) == 0 )
   1076      1.1  lukem 		{
   1077      1.1  lukem 			Modifications	*m;
   1078      1.1  lukem 			int		match = 1;
   1079      1.1  lukem 
   1080      1.1  lukem 			m = op->orm_modlist;
   1081      1.1  lukem 
   1082      1.1  lukem 			for ( ; age ; age = age->age_next ) {
   1083      1.1  lukem 				dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
   1084      1.1  lukem 
   1085      1.1  lukem 				if ( match == 0 ) {
   1086      1.1  lukem 					for ( ; m ; m = m->sml_next ) {
   1087      1.1  lukem 						if ( m->sml_desc == age->age_def->agd_member_ad ) {
   1088      1.1  lukem 							overlay_entry_release_ov( op, e, 0, on );
   1089      1.1  lukem 							ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1090      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);
   1091      1.1  lukem 							send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
   1092      1.1  lukem 							return LDAP_CONSTRAINT_VIOLATION;
   1093      1.1  lukem 						}
   1094      1.1  lukem 					}
   1095      1.1  lukem 					break;
   1096      1.1  lukem 				}
   1097      1.1  lukem 			}
   1098      1.1  lukem 
   1099      1.1  lukem 			overlay_entry_release_ov( op, e, 0, on );
   1100      1.1  lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1101      1.1  lukem 			return SLAP_CB_CONTINUE;
   1102      1.1  lukem 		}
   1103      1.1  lukem 	}
   1104      1.1  lukem 
   1105      1.1  lukem 	overlay_entry_release_ov( op, e, 0, on );
   1106      1.1  lukem 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1107      1.1  lukem 	return SLAP_CB_CONTINUE;
   1108      1.1  lukem }
   1109      1.1  lukem 
   1110      1.1  lukem /*
   1111      1.1  lukem ** Builds a filter for searching for the
   1112      1.1  lukem ** group entries, according to the objectClass.
   1113      1.1  lukem */
   1114      1.1  lukem static int
   1115      1.1  lukem autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
   1116      1.1  lukem {
   1117      1.1  lukem 	char	*ptr;
   1118      1.1  lukem 
   1119      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
   1120      1.1  lukem 
   1121      1.1  lukem 	op->ors_filterstr.bv_len = STRLENOF( "(=)" )
   1122      1.1  lukem 			+ slap_schema.si_ad_objectClass->ad_cname.bv_len
   1123      1.1  lukem 			+ agd->agd_oc->soc_cname.bv_len;
   1124      1.1  lukem 	ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
   1125      1.1  lukem 	*ptr++ = '(';
   1126      1.1  lukem 	ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
   1127      1.1  lukem 	*ptr++ = '=';
   1128      1.1  lukem 	ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
   1129      1.1  lukem 	*ptr++ = ')';
   1130      1.1  lukem 	*ptr = '\0';
   1131      1.1  lukem 
   1132      1.1  lukem 	op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
   1133      1.1  lukem 
   1134      1.1  lukem 	assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
   1135      1.1  lukem 
   1136      1.1  lukem 	return 0;
   1137      1.1  lukem }
   1138      1.1  lukem 
   1139      1.1  lukem enum {
   1140      1.1  lukem 	AG_ATTRSET = 1,
   1141      1.1  lukem 	AG_LAST
   1142      1.1  lukem };
   1143      1.1  lukem 
   1144      1.1  lukem static ConfigDriver	ag_cfgen;
   1145      1.1  lukem 
   1146      1.1  lukem static ConfigTable agcfg[] = {
   1147      1.1  lukem 	{ "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
   1148      1.1  lukem 		3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
   1149      1.1  lukem 		"( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
   1150      1.1  lukem 			"DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
   1151      1.1  lukem 			"EQUALITY caseIgnoreMatch "
   1152      1.1  lukem 			"SYNTAX OMsDirectoryString "
   1153      1.1  lukem 			"X-ORDERED 'VALUES' )",
   1154      1.1  lukem 			NULL, NULL },
   1155      1.1  lukem 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
   1156      1.1  lukem };
   1157      1.1  lukem 
   1158      1.1  lukem static ConfigOCs agocs[] = {
   1159      1.1  lukem 	{ "( OLcfgCtOc:2.1 "
   1160      1.1  lukem 		"NAME 'olcAutomaticGroups' "
   1161      1.1  lukem 		"DESC 'Automatic groups configuration' "
   1162      1.1  lukem 		"SUP olcOverlayConfig "
   1163      1.1  lukem 		"MAY olcAGattrSet )",
   1164      1.1  lukem 		Cft_Overlay, agcfg, NULL, NULL },
   1165      1.1  lukem 	{ NULL, 0, NULL }
   1166      1.1  lukem };
   1167      1.1  lukem 
   1168      1.1  lukem 
   1169      1.1  lukem static int
   1170      1.1  lukem ag_cfgen( ConfigArgs *c )
   1171      1.1  lukem {
   1172      1.1  lukem 	slap_overinst		*on = (slap_overinst *)c->bi;
   1173      1.1  lukem 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
   1174      1.1  lukem 	autogroup_def_t		*agd;
   1175      1.1  lukem 	autogroup_entry_t	*age;
   1176      1.1  lukem 
   1177      1.1  lukem 	int rc = 0, i;
   1178      1.1  lukem 
   1179      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
   1180      1.1  lukem 
   1181      1.1  lukem 	if( agi == NULL ) {
   1182      1.1  lukem 		agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
   1183      1.1  lukem 		ldap_pvt_thread_mutex_init( &agi->agi_mutex );
   1184      1.1  lukem 		agi->agi_def = NULL;
   1185      1.1  lukem 		agi->agi_entry = NULL;
   1186      1.1  lukem 		on->on_bi.bi_private = (void *)agi;
   1187      1.1  lukem 	}
   1188      1.1  lukem 
   1189      1.1  lukem 	agd = agi->agi_def;
   1190      1.1  lukem 	age = agi->agi_entry;
   1191      1.1  lukem 
   1192      1.1  lukem 	if ( c->op == SLAP_CONFIG_EMIT ) {
   1193      1.1  lukem 
   1194      1.1  lukem 		ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1195      1.1  lukem 
   1196      1.1  lukem 		for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
   1197      1.1  lukem 			struct berval	bv;
   1198      1.1  lukem 			char		*ptr = c->cr_msg;
   1199      1.1  lukem 
   1200      1.1  lukem 			assert(agd->agd_oc != NULL);
   1201      1.1  lukem 			assert(agd->agd_member_url_ad != NULL);
   1202      1.1  lukem 			assert(agd->agd_member_ad != NULL);
   1203      1.1  lukem 
   1204      1.1  lukem 			ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1205      1.1  lukem 				SLAP_X_ORDERED_FMT "%s %s %s", i,
   1206      1.1  lukem 				agd->agd_oc->soc_cname.bv_val,
   1207      1.1  lukem 				agd->agd_member_url_ad->ad_cname.bv_val,
   1208      1.1  lukem 				agd->agd_member_ad->ad_cname.bv_val );
   1209      1.1  lukem 
   1210      1.1  lukem 			bv.bv_val = c->cr_msg;
   1211      1.1  lukem 			bv.bv_len = ptr - bv.bv_val;
   1212      1.1  lukem 			value_add_one ( &c->rvalue_vals, &bv );
   1213      1.1  lukem 
   1214      1.1  lukem 		}
   1215      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1216      1.1  lukem 
   1217      1.1  lukem 		return rc;
   1218      1.1  lukem 
   1219      1.1  lukem 	}else if ( c->op == LDAP_MOD_DELETE ) {
   1220      1.1  lukem 		if ( c->valx < 0) {
   1221      1.1  lukem 			autogroup_def_t 		*agd_next;
   1222      1.1  lukem 			autogroup_entry_t	*age_next;
   1223      1.1  lukem 			autogroup_filter_t	*agf = age->age_filter,
   1224      1.1  lukem 						*agf_next;
   1225      1.1  lukem 
   1226      1.1  lukem 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1227      1.1  lukem 
   1228      1.1  lukem 			for ( agd_next = agd; agd_next; agd = agd_next ) {
   1229      1.1  lukem 				agd_next = agd->agd_next;
   1230      1.1  lukem 
   1231      1.1  lukem 				ch_free( agd );
   1232      1.1  lukem 			}
   1233      1.1  lukem 
   1234      1.1  lukem 			for ( age_next = age ; age_next ; age = age_next ) {
   1235      1.1  lukem 				age_next = age->age_next;
   1236      1.1  lukem 
   1237      1.1  lukem 				ch_free( age->age_dn.bv_val );
   1238      1.1  lukem 				ch_free( age->age_ndn.bv_val );
   1239      1.1  lukem 
   1240      1.1  lukem 				for( agf_next = agf ; agf_next ; agf = agf_next ){
   1241      1.1  lukem 					agf_next = agf->agf_next;
   1242      1.1  lukem 
   1243      1.1  lukem 					filter_free( agf->agf_filter );
   1244      1.1  lukem 					ch_free( agf->agf_filterstr.bv_val );
   1245      1.1  lukem 					ch_free( agf->agf_dn.bv_val );
   1246      1.1  lukem 					ch_free( agf->agf_ndn.bv_val );
   1247      1.1  lukem 				}
   1248      1.1  lukem 
   1249      1.1  lukem 				ldap_pvt_thread_mutex_init( &age->age_mutex );
   1250      1.1  lukem 				ch_free( age );
   1251      1.1  lukem 			}
   1252      1.1  lukem 
   1253      1.1  lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1254      1.1  lukem 
   1255      1.1  lukem 			ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
   1256      1.1  lukem 			ch_free( agi );
   1257      1.1  lukem 			on->on_bi.bi_private = NULL;
   1258      1.1  lukem 
   1259      1.1  lukem 		} else {
   1260      1.1  lukem 			autogroup_def_t		**agdp;
   1261      1.1  lukem 			autogroup_entry_t	*age_next, *age_prev;
   1262      1.1  lukem 			autogroup_filter_t	*agf,
   1263      1.1  lukem 						*agf_next;
   1264      1.1  lukem 
   1265      1.1  lukem 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1266      1.1  lukem 
   1267      1.1  lukem 			for ( i = 0, agdp = &agi->agi_def;
   1268      1.1  lukem 				i < c->valx; i++ )
   1269      1.1  lukem 			{
   1270      1.1  lukem 				if ( *agdp == NULL) {
   1271      1.1  lukem 					return 1;
   1272      1.1  lukem 				}
   1273      1.1  lukem 				agdp = &(*agdp)->agd_next;
   1274      1.1  lukem 			}
   1275      1.1  lukem 
   1276      1.1  lukem 			agd = *agdp;
   1277      1.1  lukem 			*agdp = agd->agd_next;
   1278      1.1  lukem 
   1279      1.1  lukem 			for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
   1280      1.1  lukem 				age_next = age->age_next;
   1281      1.1  lukem 
   1282      1.1  lukem 				if( age->age_def == agd ) {
   1283      1.1  lukem 					agf = age->age_filter;
   1284      1.1  lukem 
   1285      1.1  lukem 					ch_free( age->age_dn.bv_val );
   1286      1.1  lukem 					ch_free( age->age_ndn.bv_val );
   1287      1.1  lukem 
   1288      1.1  lukem 					for ( agf_next = agf; agf_next ; agf = agf_next ) {
   1289      1.1  lukem 						agf_next = agf->agf_next;
   1290      1.1  lukem 						filter_free( agf->agf_filter );
   1291      1.1  lukem 						ch_free( agf->agf_filterstr.bv_val );
   1292      1.1  lukem 						ch_free( agf->agf_dn.bv_val );
   1293      1.1  lukem 						ch_free( agf->agf_ndn.bv_val );
   1294      1.1  lukem 					}
   1295      1.1  lukem 
   1296      1.1  lukem 					ldap_pvt_thread_mutex_destroy( &age->age_mutex );
   1297      1.1  lukem 					ch_free( age );
   1298      1.1  lukem 
   1299      1.1  lukem 					age = age_prev;
   1300      1.1  lukem 
   1301      1.1  lukem 					if( age_prev != NULL ) {
   1302      1.1  lukem 						age_prev->age_next = age_next;
   1303      1.1  lukem 					}
   1304      1.1  lukem 				}
   1305      1.1  lukem 			}
   1306      1.1  lukem 
   1307      1.1  lukem 			ch_free( agd );
   1308      1.1  lukem 			agd = agi->agi_def;
   1309      1.1  lukem 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1310      1.1  lukem 
   1311      1.1  lukem 		}
   1312      1.1  lukem 
   1313      1.1  lukem 		return rc;
   1314      1.1  lukem 	}
   1315      1.1  lukem 
   1316      1.1  lukem 	switch(c->type){
   1317      1.1  lukem 	case AG_ATTRSET: {
   1318      1.1  lukem 		autogroup_def_t		**agdp,
   1319      1.1  lukem 					*agd_next = NULL;
   1320      1.1  lukem 		ObjectClass		*oc = NULL;
   1321      1.1  lukem 		AttributeDescription	*member_url_ad = NULL,
   1322      1.1  lukem 					*member_ad = NULL;
   1323      1.1  lukem 		const char		*text;
   1324      1.1  lukem 
   1325      1.1  lukem 
   1326      1.1  lukem 		oc = oc_find( c->argv[ 1 ] );
   1327      1.1  lukem 		if( oc == NULL ){
   1328      1.1  lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1329      1.1  lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1330      1.1  lukem 				"unable to find ObjectClass \"%s\"",
   1331      1.1  lukem 				c->argv[ 1 ] );
   1332      1.1  lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1333      1.1  lukem 				c->log, c->cr_msg, 0 );
   1334      1.1  lukem 			return 1;
   1335      1.1  lukem 		}
   1336      1.1  lukem 
   1337      1.1  lukem 
   1338      1.1  lukem 		rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
   1339      1.1  lukem 		if( rc != LDAP_SUCCESS ) {
   1340      1.1  lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1341      1.1  lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1342      1.1  lukem 				"unable to find AttributeDescription \"%s\"",
   1343      1.1  lukem 				c->argv[ 2 ] );
   1344      1.1  lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1345      1.1  lukem 				c->log, c->cr_msg, 0 );
   1346      1.1  lukem 			return 1;
   1347      1.1  lukem 		}
   1348      1.1  lukem 
   1349      1.1  lukem 		if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
   1350      1.1  lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1351      1.1  lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1352      1.1  lukem 				"AttributeDescription \"%s\" ",
   1353      1.1  lukem 				"must be of a subtype \"labeledURI\"",
   1354      1.1  lukem 				c->argv[ 2 ] );
   1355      1.1  lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1356      1.1  lukem 				c->log, c->cr_msg, 0 );
   1357      1.1  lukem 			return 1;
   1358      1.1  lukem 		}
   1359      1.1  lukem 
   1360      1.1  lukem 		rc = slap_str2ad( c->argv[3], &member_ad, &text );
   1361      1.1  lukem 		if( rc != LDAP_SUCCESS ) {
   1362      1.1  lukem 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1363      1.1  lukem 				"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1364      1.1  lukem 				"unable to find AttributeDescription \"%s\"",
   1365      1.1  lukem 				c->argv[ 3 ] );
   1366      1.1  lukem 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1367      1.1  lukem 				c->log, c->cr_msg, 0 );
   1368      1.1  lukem 			return 1;
   1369      1.1  lukem 		}
   1370      1.1  lukem 
   1371      1.1  lukem 		ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1372      1.1  lukem 
   1373      1.1  lukem 		for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
   1374      1.1  lukem 			/* The same URL attribute / member attribute pair
   1375      1.1  lukem 			* cannot be repeated */
   1376      1.1  lukem 
   1377      1.1  lukem 			if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
   1378      1.1  lukem 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1379      1.1  lukem 					"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1380      1.1  lukem 					"URL attributeDescription \"%s\" already mapped",
   1381      1.1  lukem 					member_ad->ad_cname.bv_val );
   1382      1.1  lukem 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1383      1.1  lukem 					c->log, c->cr_msg, 0 );
   1384      1.1  lukem /*				return 1; //warning*/
   1385      1.1  lukem 			}
   1386      1.1  lukem 		}
   1387      1.1  lukem 
   1388      1.1  lukem 		if ( c->valx > 0 ) {
   1389      1.1  lukem 			int	i;
   1390      1.1  lukem 
   1391      1.1  lukem 			for ( i = 0, agdp = &agi->agi_def ;
   1392      1.1  lukem 				i < c->valx; i++ )
   1393      1.1  lukem 			{
   1394      1.1  lukem 				if ( *agdp == NULL ) {
   1395      1.1  lukem 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1396      1.1  lukem 						"\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
   1397      1.1  lukem 						"invalid index {%d}",
   1398      1.1  lukem 						c->valx );
   1399      1.1  lukem 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   1400      1.1  lukem 						c->log, c->cr_msg, 0 );
   1401      1.1  lukem 
   1402      1.1  lukem 					ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1403      1.1  lukem 					return 1;
   1404      1.1  lukem 				}
   1405      1.1  lukem 				agdp = &(*agdp)->agd_next;
   1406      1.1  lukem 			}
   1407      1.1  lukem 			agd_next = *agdp;
   1408      1.1  lukem 
   1409      1.1  lukem 		} else {
   1410      1.1  lukem 			for ( agdp = &agi->agi_def; *agdp;
   1411      1.1  lukem 				agdp = &(*agdp)->agd_next )
   1412      1.1  lukem 				/* goto last */;
   1413      1.1  lukem 		}
   1414      1.1  lukem 
   1415      1.1  lukem 		*agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
   1416      1.1  lukem 
   1417      1.1  lukem 		(*agdp)->agd_oc = oc;
   1418      1.1  lukem 		(*agdp)->agd_member_url_ad = member_url_ad;
   1419      1.1  lukem 		(*agdp)->agd_member_ad = member_ad;
   1420      1.1  lukem 		(*agdp)->agd_next = agd_next;
   1421      1.1  lukem 
   1422      1.1  lukem 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1423      1.1  lukem 
   1424      1.1  lukem 		} break;
   1425      1.1  lukem 
   1426      1.1  lukem 	default:
   1427      1.1  lukem 		rc = 1;
   1428      1.1  lukem 		break;
   1429      1.1  lukem 	}
   1430      1.1  lukem 
   1431      1.1  lukem 	return rc;
   1432      1.1  lukem }
   1433      1.1  lukem 
   1434      1.1  lukem /*
   1435      1.1  lukem ** Do a search for all the groups in the
   1436      1.1  lukem ** database, and add them to out internal list.
   1437      1.1  lukem */
   1438      1.1  lukem static int
   1439      1.1  lukem autogroup_db_open(
   1440      1.1  lukem 	BackendDB	*be,
   1441      1.1  lukem 	ConfigReply	*cr )
   1442      1.1  lukem {
   1443  1.1.1.2  lukem 	slap_overinst			*on = (slap_overinst *) be->bd_info;
   1444      1.1  lukem 	autogroup_info_t		*agi = on->on_bi.bi_private;
   1445      1.1  lukem 	autogroup_def_t		*agd;
   1446      1.1  lukem 	autogroup_sc_t		ags;
   1447      1.1  lukem 	Operation		*op;
   1448      1.1  lukem 	SlapReply		rs = { REP_RESULT };
   1449      1.1  lukem 	slap_callback		cb = { 0 };
   1450      1.1  lukem 
   1451      1.1  lukem 	void				*thrctx = ldap_pvt_thread_pool_context();
   1452      1.1  lukem 	Connection			conn = { 0 };
   1453      1.1  lukem 	OperationBuffer 	opbuf;
   1454      1.1  lukem 
   1455      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
   1456      1.1  lukem 
   1457  1.1.1.2  lukem 	if ( agi == NULL ) {
   1458  1.1.1.2  lukem 		return 0;
   1459  1.1.1.2  lukem 	}
   1460  1.1.1.2  lukem 
   1461      1.1  lukem 	connection_fake_init( &conn, &opbuf, thrctx );
   1462      1.1  lukem 	op = &opbuf.ob_op;
   1463      1.1  lukem 
   1464      1.1  lukem 	op->ors_attrsonly = 0;
   1465      1.1  lukem 	op->o_tag = LDAP_REQ_SEARCH;
   1466      1.1  lukem 	op->o_dn = be->be_rootdn;
   1467      1.1  lukem 	op->o_ndn = be->be_rootndn;
   1468      1.1  lukem 
   1469      1.1  lukem 	op->o_req_dn = be->be_suffix[0];
   1470      1.1  lukem 	op->o_req_ndn = be->be_nsuffix[0];
   1471      1.1  lukem 
   1472      1.1  lukem 	op->ors_scope = LDAP_SCOPE_SUBTREE;
   1473      1.1  lukem 	op->ors_deref = LDAP_DEREF_NEVER;
   1474      1.1  lukem 	op->ors_limit = NULL;
   1475      1.1  lukem 	op->ors_tlimit = SLAP_NO_LIMIT;
   1476      1.1  lukem 	op->ors_slimit = SLAP_NO_LIMIT;
   1477      1.1  lukem 	op->ors_attrs =  slap_anlist_no_attrs;
   1478      1.1  lukem 
   1479  1.1.1.2  lukem 	op->o_bd = be;
   1480  1.1.1.2  lukem 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1481  1.1.1.2  lukem 
   1482  1.1.1.2  lukem 	ags.ags_info = agi;
   1483  1.1.1.2  lukem 	cb.sc_private = &ags;
   1484  1.1.1.2  lukem 	cb.sc_response = autogroup_group_add_cb;
   1485  1.1.1.2  lukem 	cb.sc_cleanup = NULL;
   1486  1.1.1.2  lukem 	cb.sc_next = NULL;
   1487  1.1.1.2  lukem 
   1488  1.1.1.2  lukem 	op->o_callback = &cb;
   1489      1.1  lukem 
   1490      1.1  lukem 	for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
   1491      1.1  lukem 
   1492      1.1  lukem 		autogroup_build_def_filter(agd, op);
   1493      1.1  lukem 
   1494      1.1  lukem 		ags.ags_def = agd;
   1495      1.1  lukem 
   1496      1.1  lukem 		op->o_bd->be_search( op, &rs );
   1497      1.1  lukem 
   1498  1.1.1.2  lukem 		filter_free_x( op, op->ors_filter, 1 );
   1499      1.1  lukem 		op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
   1500      1.1  lukem 	}
   1501      1.1  lukem 
   1502      1.1  lukem 	return 0;
   1503      1.1  lukem }
   1504      1.1  lukem 
   1505      1.1  lukem static int
   1506      1.1  lukem autogroup_db_close(
   1507      1.1  lukem 	BackendDB	*be,
   1508      1.1  lukem 	ConfigReply	*cr )
   1509      1.1  lukem {
   1510      1.1  lukem 	slap_overinst			*on = (slap_overinst *) be->bd_info;
   1511      1.1  lukem 
   1512      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
   1513      1.1  lukem 
   1514      1.1  lukem 	if ( on->on_bi.bi_private ) {
   1515      1.1  lukem 		autogroup_info_t		*agi = on->on_bi.bi_private;
   1516      1.1  lukem 		autogroup_entry_t	*age = agi->agi_entry,
   1517      1.1  lukem 					*age_next;
   1518      1.1  lukem 		autogroup_filter_t	*agf, *agf_next;
   1519      1.1  lukem 
   1520      1.1  lukem 		for ( age_next = age; age_next; age = age_next ) {
   1521      1.1  lukem 			age_next = age->age_next;
   1522      1.1  lukem 
   1523      1.1  lukem 			ch_free( age->age_dn.bv_val );
   1524      1.1  lukem 			ch_free( age->age_ndn.bv_val );
   1525      1.1  lukem 
   1526      1.1  lukem 			agf = age->age_filter;
   1527      1.1  lukem 
   1528      1.1  lukem 			for ( agf_next = agf; agf_next; agf = agf_next ) {
   1529      1.1  lukem 				agf_next = agf->agf_next;
   1530      1.1  lukem 
   1531      1.1  lukem 				filter_free( agf->agf_filter );
   1532      1.1  lukem 				ch_free( agf->agf_filterstr.bv_val );
   1533      1.1  lukem 				ch_free( agf->agf_dn.bv_val );
   1534      1.1  lukem 				ch_free( agf->agf_ndn.bv_val );
   1535      1.1  lukem 				ch_free( agf );
   1536      1.1  lukem 			}
   1537      1.1  lukem 
   1538      1.1  lukem 			ldap_pvt_thread_mutex_destroy( &age->age_mutex );
   1539      1.1  lukem 			ch_free( age );
   1540      1.1  lukem 		}
   1541      1.1  lukem 	}
   1542      1.1  lukem 
   1543      1.1  lukem 	return 0;
   1544      1.1  lukem }
   1545      1.1  lukem 
   1546      1.1  lukem static int
   1547      1.1  lukem autogroup_db_destroy(
   1548      1.1  lukem 	BackendDB	*be,
   1549      1.1  lukem 	ConfigReply	*cr )
   1550      1.1  lukem {
   1551      1.1  lukem 	slap_overinst			*on = (slap_overinst *) be->bd_info;
   1552      1.1  lukem 
   1553      1.1  lukem 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
   1554      1.1  lukem 
   1555      1.1  lukem 	if ( on->on_bi.bi_private ) {
   1556      1.1  lukem 		autogroup_info_t		*agi = on->on_bi.bi_private;
   1557      1.1  lukem 		autogroup_def_t		*agd = agi->agi_def,
   1558      1.1  lukem 					*agd_next;
   1559      1.1  lukem 
   1560      1.1  lukem 		for ( agd_next = agd; agd_next; agd = agd_next ) {
   1561      1.1  lukem 			agd_next = agd->agd_next;
   1562      1.1  lukem 
   1563      1.1  lukem 			ch_free( agd );
   1564      1.1  lukem 		}
   1565      1.1  lukem 
   1566      1.1  lukem 		ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
   1567      1.1  lukem 		ch_free( agi );
   1568      1.1  lukem 	}
   1569      1.1  lukem 
   1570      1.1  lukem 	return 0;
   1571      1.1  lukem }
   1572      1.1  lukem 
   1573      1.1  lukem static slap_overinst	autogroup = { { NULL } };
   1574      1.1  lukem 
   1575      1.1  lukem static
   1576      1.1  lukem int
   1577      1.1  lukem autogroup_initialize(void)
   1578      1.1  lukem {
   1579      1.1  lukem 	int		rc = 0;
   1580      1.1  lukem 	autogroup.on_bi.bi_type = "autogroup";
   1581      1.1  lukem 
   1582      1.1  lukem 	autogroup.on_bi.bi_db_open = autogroup_db_open;
   1583      1.1  lukem 	autogroup.on_bi.bi_db_close = autogroup_db_close;
   1584      1.1  lukem 	autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
   1585      1.1  lukem 
   1586      1.1  lukem 	autogroup.on_bi.bi_op_add = autogroup_add_entry;
   1587      1.1  lukem 	autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
   1588      1.1  lukem 	autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
   1589      1.1  lukem 
   1590      1.1  lukem 	autogroup.on_response = autogroup_response;
   1591      1.1  lukem 
   1592      1.1  lukem 	autogroup.on_bi.bi_cf_ocs = agocs;
   1593      1.1  lukem 
   1594      1.1  lukem 	rc = config_register_schema( agcfg, agocs );
   1595      1.1  lukem 	if ( rc ) {
   1596      1.1  lukem 		return rc;
   1597      1.1  lukem 	}
   1598      1.1  lukem 
   1599      1.1  lukem 	return overlay_register( &autogroup );
   1600      1.1  lukem }
   1601      1.1  lukem 
   1602      1.1  lukem int
   1603      1.1  lukem init_module( int argc, char *argv[] )
   1604      1.1  lukem {
   1605      1.1  lukem 	return autogroup_initialize();
   1606      1.1  lukem }
   1607