Home | History | Annotate | Line # | Download | only in autogroup
autogroup.c revision 1.2
      1  1.2  christos /*	$NetBSD: autogroup.c,v 1.2 2020/08/11 13:15:35 christos Exp $	*/
      2  1.2  christos 
      3  1.1     lukem /* autogroup.c - automatic group overlay */
      4  1.2  christos /* $OpenLDAP$ */
      5  1.2  christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  1.2  christos  *
      7  1.2  christos  * Copyright 2007-2020 The OpenLDAP Foundation.
      8  1.2  christos  * Portions Copyright 2007 Micha Szulczyski.
      9  1.2  christos  * 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.2  christos /* ACKNOWLEDGEMENTS:
     21  1.2  christos  * This work was initially developed by Micha Szulczyski for inclusion in
     22  1.2  christos  * OpenLDAP Software.  Additional significant contributors include:
     23  1.2  christos  *   Howard Chu
     24  1.2  christos  *   Raphael Ouazana
     25  1.2  christos  *   Norbert Pueschel
     26  1.2  christos  *   Christian Manal
     27  1.2  christos  */
     28  1.2  christos 
     29  1.2  christos #include <sys/cdefs.h>
     30  1.2  christos __RCSID("$NetBSD: autogroup.c,v 1.2 2020/08/11 13:15:35 christos Exp $");
     31  1.1     lukem 
     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.2  christos #ifndef SLAPD_MEMBEROF_ATTR
     43  1.2  christos #define	SLAPD_MEMBEROF_ATTR	"memberOf"
     44  1.2  christos #endif
     45  1.2  christos 
     46  1.2  christos static slap_overinst	autogroup;
     47  1.2  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.2  christos 	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.2  christos 	int			age_mustrefresh; /* Defined in request to refresh in response */
     75  1.2  christos 	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.2  christos 	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.2  christos 	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.2  christos 	Modifications	*modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
    117  1.1     lukem 	SlapReply	sreply = {REP_RESULT};
    118  1.2  christos 	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.2  christos 	unsigned long opid = op->o_opid;
    122  1.2  christos 	OpExtra oex;
    123  1.1     lukem 
    124  1.2  christos 	assert( dn != NULL );
    125  1.2  christos 	assert( ndn != NULL );
    126  1.1     lukem 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
    127  1.1     lukem 		dn->bv_val, age->age_dn.bv_val, 0);
    128  1.1     lukem 
    129  1.2  christos 	vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    130  1.2  christos 	nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    131  1.2  christos 	ber_dupbv( vals, dn );
    132  1.1     lukem 	BER_BVZERO( &vals[ 1 ] );
    133  1.2  christos 	ber_dupbv( nvals, ndn );
    134  1.1     lukem 	BER_BVZERO( &nvals[ 1 ] );
    135  1.1     lukem 
    136  1.2  christos 	modlist->sml_op = LDAP_MOD_ADD;
    137  1.2  christos 	modlist->sml_desc = age->age_def->agd_member_ad;
    138  1.2  christos 	modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
    139  1.2  christos 	modlist->sml_values = vals;
    140  1.2  christos 	modlist->sml_nvalues = nvals;
    141  1.2  christos 	modlist->sml_numvals = 1;
    142  1.2  christos 	modlist->sml_flags = SLAP_MOD_INTERNAL;
    143  1.2  christos 	modlist->sml_next = NULL;
    144  1.2  christos 
    145  1.2  christos 	o.o_opid = 0;	/* shared with op, saved above */
    146  1.2  christos 	o.o_tag = LDAP_REQ_MODIFY;
    147  1.2  christos 	o.o_callback = &cb;
    148  1.2  christos 	o.orm_modlist = modlist;
    149  1.2  christos 	o.o_dn = op->o_bd->be_rootdn;
    150  1.2  christos 	o.o_ndn = op->o_bd->be_rootndn;
    151  1.2  christos 	o.o_req_dn = age->age_dn;
    152  1.2  christos 	o.o_req_ndn = age->age_ndn;
    153  1.2  christos 	o.o_permissive_modify = 1;
    154  1.2  christos 	o.o_dont_replicate = 1;
    155  1.2  christos 	o.orm_no_opattrs = 1;
    156  1.2  christos 	o.o_managedsait = SLAP_CONTROL_CRITICAL;
    157  1.2  christos 	o.o_relax = SLAP_CONTROL_CRITICAL;
    158  1.2  christos 
    159  1.2  christos 	oex.oe_key = (void *)&autogroup;
    160  1.2  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    161  1.2  christos 
    162  1.2  christos 	o.o_bd->bd_info = (BackendInfo *)on->on_info;
    163  1.2  christos 	(void)op->o_bd->be_modify( &o, &sreply );
    164  1.2  christos 	o.o_bd->bd_info = (BackendInfo *)on;
    165  1.2  christos 
    166  1.2  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    167  1.2  christos 
    168  1.2  christos 	slap_mods_free( modlist, 1 );
    169  1.2  christos 	op->o_opid = opid;
    170  1.2  christos 
    171  1.2  christos 	return sreply.sr_err;
    172  1.2  christos }
    173  1.2  christos 
    174  1.2  christos /*
    175  1.2  christos **	e	- the entry where to get the attribute values
    176  1.2  christos **	age	- the group to which the values will be added
    177  1.2  christos */
    178  1.2  christos static int
    179  1.2  christos autogroup_add_member_values_to_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
    180  1.2  christos {
    181  1.2  christos 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    182  1.2  christos 	Modifications	modlist;
    183  1.2  christos 	SlapReply	sreply = {REP_RESULT};
    184  1.2  christos 	slap_callback	cb = { NULL, slap_null_cb, NULL, NULL };
    185  1.2  christos 	Operation	o = *op;
    186  1.2  christos 	unsigned long opid = op->o_opid;
    187  1.2  christos 	OpExtra oex;
    188  1.2  christos 
    189  1.2  christos 	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
    190  1.2  christos 		dn->bv_val, age->age_dn.bv_val, 0);
    191  1.2  christos 
    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.2  christos 	modlist.sml_values = attr->a_vals;
    196  1.2  christos 	modlist.sml_nvalues = attr->a_nvals;
    197  1.2  christos 	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.2  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.2  christos 	o.o_dn = op->o_bd->be_rootdn;
    206  1.2  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.2  christos 	o.o_dont_replicate = 1;
    211  1.2  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.2  christos 	oex.oe_key = (void *)&autogroup;
    216  1.2  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    217  1.2  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.2  christos 	op->o_opid = opid;
    222  1.2  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.2  christos 	Modifications	*modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
    237  1.1     lukem 	SlapReply	sreply = {REP_RESULT};
    238  1.2  christos 	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.2  christos 	unsigned long opid = op->o_opid;
    242  1.2  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.2  christos 		modlist->sml_values = NULL;
    249  1.2  christos 		modlist->sml_nvalues = NULL;
    250  1.2  christos 		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.2  christos 		vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    256  1.2  christos 		nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
    257  1.2  christos 		ber_dupbv( vals, dn );
    258  1.1     lukem 		BER_BVZERO( &vals[ 1 ] );
    259  1.2  christos 		ber_dupbv( nvals, ndn );
    260  1.1     lukem 		BER_BVZERO( &nvals[ 1 ] );
    261  1.1     lukem 
    262  1.2  christos 		modlist->sml_values = vals;
    263  1.2  christos 		modlist->sml_nvalues = nvals;
    264  1.2  christos 		modlist->sml_numvals = 1;
    265  1.1     lukem 	}
    266  1.1     lukem 
    267  1.1     lukem 
    268  1.2  christos 	modlist->sml_op = LDAP_MOD_DELETE;
    269  1.2  christos 	modlist->sml_desc = age->age_def->agd_member_ad;
    270  1.2  christos 	modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
    271  1.2  christos 	modlist->sml_flags = SLAP_MOD_INTERNAL;
    272  1.2  christos 	modlist->sml_next = NULL;
    273  1.1     lukem 
    274  1.2  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.2  christos 	o.orm_modlist = modlist;
    278  1.2  christos 	o.o_dn = op->o_bd->be_rootdn;
    279  1.2  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.2  christos 	o.o_dont_replicate = 1;
    286  1.2  christos 	o.orm_no_opattrs = 1;
    287  1.2  christos 
    288  1.2  christos 	oex.oe_key = (void *)&autogroup;
    289  1.2  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.2  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    296  1.2  christos 
    297  1.2  christos 	slap_mods_free( modlist, 1 );
    298  1.2  christos 
    299  1.2  christos 	op->o_opid = opid;
    300  1.1     lukem 	return sreply.sr_err;
    301  1.1     lukem }
    302  1.1     lukem 
    303  1.2  christos /*
    304  1.2  christos **      e       - the entry where to get the attribute values
    305  1.2  christos **      age     - the group from which the values will be deleted
    306  1.2  christos */
    307  1.2  christos static int
    308  1.2  christos autogroup_delete_member_values_from_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
    309  1.2  christos {
    310  1.2  christos         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
    311  1.2  christos         Modifications   modlist;
    312  1.2  christos         SlapReply       sreply = {REP_RESULT};
    313  1.2  christos         slap_callback   cb = { NULL, slap_null_cb, NULL, NULL };
    314  1.2  christos         Operation       o = *op;
    315  1.2  christos 	unsigned long opid = op->o_opid;
    316  1.2  christos 	OpExtra oex;
    317  1.2  christos 
    318  1.2  christos         Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n",
    319  1.2  christos 			dn->bv_val, age->age_dn.bv_val, 0);
    320  1.2  christos 
    321  1.2  christos         modlist.sml_op = LDAP_MOD_DELETE;
    322  1.2  christos         modlist.sml_desc = age->age_def->agd_member_ad;
    323  1.2  christos         modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
    324  1.2  christos         modlist.sml_values = attr->a_vals;
    325  1.2  christos         modlist.sml_nvalues = attr->a_nvals;
    326  1.2  christos         modlist.sml_numvals = attr->a_numvals;
    327  1.2  christos         modlist.sml_flags = SLAP_MOD_INTERNAL;
    328  1.2  christos         modlist.sml_next = NULL;
    329  1.2  christos 
    330  1.2  christos 	o.o_opid = 0;
    331  1.2  christos         o.o_tag = LDAP_REQ_MODIFY;
    332  1.2  christos         o.o_callback = &cb;
    333  1.2  christos         o.orm_modlist = &modlist;
    334  1.2  christos 		o.o_dn = op->o_bd->be_rootdn;
    335  1.2  christos 		o.o_ndn = op->o_bd->be_rootndn;
    336  1.2  christos         o.o_req_dn = age->age_dn;
    337  1.2  christos         o.o_req_ndn = age->age_ndn;
    338  1.2  christos         o.o_permissive_modify = 1;
    339  1.2  christos 	o.o_dont_replicate = 1;
    340  1.2  christos 	o.orm_no_opattrs = 1;
    341  1.2  christos         o.o_managedsait = SLAP_CONTROL_CRITICAL;
    342  1.2  christos         o.o_relax = SLAP_CONTROL_CRITICAL;
    343  1.2  christos 
    344  1.2  christos 	oex.oe_key = (void *)&autogroup;
    345  1.2  christos 	LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
    346  1.2  christos 
    347  1.2  christos         o.o_bd->bd_info = (BackendInfo *)on->on_info;
    348  1.2  christos         (void)op->o_bd->be_modify( &o, &sreply );
    349  1.2  christos         o.o_bd->bd_info = (BackendInfo *)on;
    350  1.2  christos 	op->o_opid = opid;
    351  1.2  christos 
    352  1.2  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    353  1.2  christos 
    354  1.2  christos         return sreply.sr_err;
    355  1.2  christos }
    356  1.2  christos 
    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.2  christos 		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.2  christos 		struct berval		*vals, *nvals;
    376  1.2  christos 		struct berval		lvals[ 2 ], lnvals[ 2 ];
    377  1.2  christos 		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.2  christos 		if ( agf->agf_anlist ) {
    383  1.2  christos 			Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
    384  1.2  christos 			if (attr) {
    385  1.2  christos 				vals = attr->a_vals;
    386  1.2  christos 				nvals = attr->a_nvals;
    387  1.2  christos 				numvals = attr->a_numvals;
    388  1.2  christos 			} else {
    389  1.2  christos 				// Nothing to add
    390  1.2  christos 				return 0;
    391  1.2  christos 			}
    392  1.2  christos 		} else {
    393  1.2  christos 			lvals[ 0 ] = rs->sr_entry->e_name;
    394  1.2  christos 			BER_BVZERO( &lvals[ 1 ] );
    395  1.2  christos 			lnvals[ 0 ] = rs->sr_entry->e_nname;
    396  1.2  christos 			BER_BVZERO( &lnvals[ 1 ] );
    397  1.2  christos 			vals = lvals;
    398  1.2  christos 			nvals = lnvals;
    399  1.2  christos 			numvals = 1;
    400  1.2  christos 		}
    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.2  christos 		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.2  christos 		autogroup_filter_t	*agf = agg->agg_filter;
    430  1.1     lukem 		Modifications		*modlist;
    431  1.2  christos 		struct berval		*vals, *nvals;
    432  1.2  christos 		struct berval		lvals[ 2 ], lnvals[ 2 ];
    433  1.2  christos 		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.2  christos 		if ( agf->agf_anlist ) {
    439  1.2  christos 			Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
    440  1.2  christos 			if (attr) {
    441  1.2  christos 				vals = attr->a_vals;
    442  1.2  christos 				nvals = attr->a_nvals;
    443  1.2  christos 				numvals = attr->a_numvals;
    444  1.2  christos 			} else {
    445  1.2  christos 				// Nothing to add
    446  1.2  christos 				return 0;
    447  1.2  christos 			}
    448  1.1     lukem 		} else {
    449  1.2  christos 			lvals[ 0 ] = rs->sr_entry->e_name;
    450  1.2  christos 			BER_BVZERO( &lvals[ 1 ] );
    451  1.2  christos 			lnvals[ 0 ] = rs->sr_entry->e_nname;
    452  1.2  christos 			BER_BVZERO( &lnvals[ 1 ] );
    453  1.2  christos 			vals = lvals;
    454  1.2  christos 			nvals = lnvals;
    455  1.2  christos 			numvals = 1;
    456  1.2  christos 		}
    457  1.2  christos 
    458  1.2  christos 		if ( numvals ) {
    459  1.2  christos 			modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
    460  1.2  christos 
    461  1.2  christos 			modlist->sml_op = LDAP_MOD_ADD;
    462  1.2  christos 			modlist->sml_desc = age->age_def->agd_member_ad;
    463  1.2  christos 			modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
    464  1.2  christos 
    465  1.2  christos 			ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
    466  1.2  christos 			ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
    467  1.2  christos 			modlist->sml_numvals = numvals;
    468  1.2  christos 
    469  1.2  christos 			modlist->sml_flags = SLAP_MOD_INTERNAL;
    470  1.2  christos 			modlist->sml_next = NULL;
    471  1.2  christos 
    472  1.2  christos 			if ( agg->agg_mod == NULL ) {
    473  1.2  christos 				agg->agg_mod = modlist;
    474  1.2  christos 				agg->agg_mod_last = modlist;
    475  1.2  christos 			} else {
    476  1.2  christos 				agg->agg_mod_last->sml_next = modlist;
    477  1.2  christos 				agg->agg_mod_last = modlist;
    478  1.2  christos 			}
    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.2  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.2  christos 	o.o_dn = op->o_bd->be_rootdn;
    514  1.2  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.2  christos 	o.ors_attrs =  agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
    527  1.2  christos 	o.o_do_not_cache = 1;
    528  1.1     lukem 
    529  1.1     lukem 	agg.agg_group = age;
    530  1.2  christos 	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.2  christos 	if ( modify == 1 && agg.agg_mod ) {
    552  1.2  christos 		unsigned long opid = op->o_opid;
    553  1.2  christos 
    554  1.2  christos 		rs_reinit( &rs, REP_RESULT );
    555  1.2  christos 
    556  1.1     lukem 		o = *op;
    557  1.2  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.2  christos 		o.o_dn = op->o_bd->be_rootdn;
    562  1.2  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.2  christos 		o.o_dont_replicate = 1;
    569  1.2  christos 		o.orm_no_opattrs = 1;
    570  1.2  christos 
    571  1.2  christos 	oex.oe_key = (void *)&autogroup;
    572  1.2  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.2  christos 	LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
    579  1.2  christos 
    580  1.1     lukem 		slap_mods_free(agg.agg_mod, 1);
    581  1.2  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.2  christos 	(*agep)->age_mustrefresh = 0;
    638  1.2  christos 	(*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.2  christos 			} else {
    683  1.2  christos 				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: URL filter is missing <%s>\n", bv->bv_val,0,0);
    684  1.2  christos 				/* FIXME: error? */
    685  1.2  christos 				goto cleanup;
    686  1.2  christos 			}
    687  1.2  christos 
    688  1.2  christos 			if ( lud->lud_attrs != NULL ) {
    689  1.2  christos 				int i;
    690  1.2  christos 
    691  1.2  christos 				for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
    692  1.2  christos 					/* Just counting */;
    693  1.2  christos 				}
    694  1.2  christos 
    695  1.2  christos 				if ( i > 1 ) {
    696  1.2  christos 					Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n",
    697  1.2  christos 						bv->bv_val, 0, 0);
    698  1.2  christos 					/* FIXME: error? */
    699  1.2  christos 					filter_free( agf->agf_filter );
    700  1.2  christos 					ch_free( agf->agf_filterstr.bv_val );
    701  1.2  christos 					ch_free( agf->agf_dn.bv_val );
    702  1.2  christos 					ch_free( agf->agf_ndn.bv_val );
    703  1.2  christos 					ldap_free_urldesc( lud );
    704  1.2  christos 					ch_free( agf );
    705  1.2  christos 					continue;
    706  1.2  christos 				}
    707  1.2  christos 
    708  1.2  christos 				agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
    709  1.2  christos 
    710  1.2  christos 				if ( agf->agf_anlist == NULL ) {
    711  1.2  christos 					Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
    712  1.2  christos 						lud->lud_attrs[0], 0, 0 );
    713  1.2  christos 					/* FIXME: error? */
    714  1.2  christos 					filter_free( agf->agf_filter );
    715  1.2  christos 					ch_free( agf->agf_filterstr.bv_val );
    716  1.2  christos 					ch_free( agf->agf_dn.bv_val );
    717  1.2  christos 					ch_free( agf->agf_ndn.bv_val );
    718  1.2  christos 					ldap_free_urldesc( lud );
    719  1.2  christos 					ch_free( agf );
    720  1.2  christos 					continue;
    721  1.2  christos 				}
    722  1.2  christos 			}
    723  1.1     lukem 
    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.2  christos 			ch_free( agf->agf_ndn.bv_val );
    751  1.2  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.2  christos typedef struct ag_addinfo {
    785  1.2  christos 	slap_overinst *on;
    786  1.2  christos 	Entry *e;
    787  1.2  christos 	autogroup_def_t		*agd;
    788  1.2  christos } ag_addinfo;
    789  1.2  christos 
    790  1.2  christos static int
    791  1.2  christos autogroup_add_entry_cb( Operation *op, SlapReply *rs )
    792  1.2  christos {
    793  1.2  christos 	slap_callback *sc = op->o_callback;
    794  1.2  christos 	ag_addinfo *aa = sc->sc_private;
    795  1.2  christos 	slap_overinst *on = aa->on;
    796  1.2  christos 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
    797  1.2  christos 	BackendInfo *bi = op->o_bd->bd_info;
    798  1.2  christos 
    799  1.2  christos 	if ( rs->sr_err != LDAP_SUCCESS )
    800  1.2  christos 		goto done;
    801  1.2  christos 
    802  1.2  christos 	op->o_bd->bd_info = (BackendInfo *)on;
    803  1.2  christos 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
    804  1.2  christos 	if ( aa->agd ) {
    805  1.2  christos 		autogroup_add_group( op, agi, aa->agd, aa->e, NULL, 1 , 0);
    806  1.2  christos 	} else {
    807  1.2  christos 		autogroup_entry_t	*age;
    808  1.2  christos 		autogroup_filter_t	*agf;
    809  1.2  christos 		struct berval odn, ondn;
    810  1.2  christos 		int rc;
    811  1.2  christos 
    812  1.2  christos 		/* must use rootdn when calling test_filter */
    813  1.2  christos 		odn = op->o_dn;
    814  1.2  christos 		ondn = op->o_ndn;
    815  1.2  christos 		op->o_dn = op->o_bd->be_rootdn;
    816  1.2  christos 		op->o_ndn = op->o_bd->be_rootndn;
    817  1.2  christos 
    818  1.2  christos 		for ( age = agi->agi_entry; age ; age = age->age_next ) {
    819  1.2  christos 			ldap_pvt_thread_mutex_lock( &age->age_mutex );
    820  1.2  christos 
    821  1.2  christos 			/* Check if any of the filters are the suffix to the entry DN.
    822  1.2  christos 			   If yes, we can test that filter against the entry. */
    823  1.2  christos 
    824  1.2  christos 			for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
    825  1.2  christos 				if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
    826  1.2  christos 					rc = test_filter( op, aa->e, agf->agf_filter );
    827  1.2  christos 					if ( rc == LDAP_COMPARE_TRUE ) {
    828  1.2  christos 						if ( agf->agf_anlist ) {
    829  1.2  christos 							Attribute *a = attr_find( aa->e->e_attrs, agf->agf_anlist[0].an_desc );
    830  1.2  christos 							if ( a )
    831  1.2  christos 								autogroup_add_member_values_to_group( op, &op->o_req_dn, age, a );
    832  1.2  christos 						} else {
    833  1.2  christos 							autogroup_add_member_to_group( op, &aa->e->e_name, &aa->e->e_nname, age );
    834  1.2  christos 						}
    835  1.2  christos 						break;
    836  1.2  christos 					}
    837  1.2  christos 				}
    838  1.2  christos 			}
    839  1.2  christos 			ldap_pvt_thread_mutex_unlock( &age->age_mutex );
    840  1.2  christos 		}
    841  1.2  christos 		op->o_dn = odn;
    842  1.2  christos 		op->o_ndn = ondn;
    843  1.2  christos 	}
    844  1.2  christos 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
    845  1.2  christos 
    846  1.2  christos 	op->o_bd->bd_info = bi;
    847  1.2  christos 
    848  1.2  christos done:
    849  1.2  christos 	op->o_callback = sc->sc_next;
    850  1.2  christos 	op->o_tmpfree( sc, op->o_tmpmemctx );
    851  1.2  christos 
    852  1.2  christos 	return SLAP_CB_CONTINUE;
    853  1.2  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.2  christos 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
    863  1.2  christos 	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.2  christos 	slap_callback	*sc = NULL;
    866  1.2  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.2  christos 	sc = op->o_tmpcalloc( sizeof(slap_callback) + sizeof(ag_addinfo), 1, op->o_tmpmemctx );
    872  1.2  christos 	sc->sc_private = (sc+1);
    873  1.2  christos 	sc->sc_response = autogroup_add_entry_cb;
    874  1.2  christos 	aa = sc->sc_private;
    875  1.2  christos 	aa->on = on;
    876  1.2  christos 	aa->e = op->ora_e;
    877  1.2  christos 	sc->sc_next = op->o_callback;
    878  1.2  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.2  christos 			aa->agd = agd;
    897  1.1     lukem 
    898  1.2  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.2  christos 				anlist_free( agf->agf_anlist, 1, NULL );
    944  1.2  christos 				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.2  christos 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
    968  1.2  christos 	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.2  christos 	struct berval odn, ondn;
    973  1.2  christos 	OpExtra *oex;
    974  1.2  christos 
    975  1.2  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
    976  1.2  christos 		if ( oex->oe_key == (void *)&autogroup )
    977  1.2  christos 			return SLAP_CB_CONTINUE;
    978  1.2  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.2  christos 	for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) {
    993  1.2  christos 		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.2  christos 	odn = op->o_dn;
   1023  1.2  christos 	ondn = op->o_ndn;
   1024  1.2  christos 	op->o_dn = op->o_bd->be_rootdn;
   1025  1.2  christos 	op->o_ndn = op->o_bd->be_rootndn;
   1026  1.2  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.2  christos 					/* If the attribute is retrieved from the entry, we don't know what to delete
   1035  1.2  christos 					** So the group must be entirely refreshed
   1036  1.2  christos 					** But the refresh can't be done now because the entry is not deleted
   1037  1.2  christos 					** So the group is marked as mustrefresh
   1038  1.2  christos 					*/
   1039  1.2  christos 					if ( agf->agf_anlist ) {
   1040  1.2  christos 						age->age_mustrefresh = 1;
   1041  1.2  christos 					} else {
   1042  1.2  christos 						autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
   1043  1.2  christos 					}
   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.2  christos 	op->o_dn = odn;
   1051  1.2  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.2  christos 	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.2  christos 	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.2  christos 	Attribute		*a, *ea, *attrs;
   1070  1.2  christos 	int			is_olddn, is_newdn, is_value_refresh, dn_equal;
   1071  1.2  christos 	OpExtra *oex;
   1072  1.2  christos 
   1073  1.2  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
   1074  1.2  christos 		if ( oex->oe_key == (void *)&autogroup )
   1075  1.2  christos 			break;
   1076  1.2  christos 	}
   1077  1.2  christos 
   1078  1.2  christos 	/* Handle all cases where a refresh of the group is needed */
   1079  1.2  christos 	if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
   1080  1.2  christos 		if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
   1081  1.2  christos 
   1082  1.2  christos 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1083  1.2  christos 
   1084  1.2  christos 			for ( age = agi->agi_entry ; age ; age = age->age_next ) {
   1085  1.2  christos 				/* Request detected that the group must be refreshed */
   1086  1.2  christos 
   1087  1.2  christos 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1088  1.2  christos 
   1089  1.2  christos 				if ( age->age_mustrefresh ) {
   1090  1.2  christos 					autogroup_delete_member_from_group( op, NULL, NULL, age) ;
   1091  1.2  christos 
   1092  1.2  christos 					for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1093  1.2  christos 						autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
   1094  1.2  christos 					}
   1095  1.2  christos 				}
   1096  1.1     lukem 
   1097  1.2  christos 				ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1098  1.2  christos 			}
   1099  1.2  christos 
   1100  1.2  christos 			ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1101  1.2  christos 		}
   1102  1.2  christos 	} else if ( op->o_tag == LDAP_REQ_MODRDN ) {
   1103  1.2  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.2  christos 			attrs = attrs_dup( e->e_attrs );
   1185  1.2  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.2  christos 				is_value_refresh = 0;
   1190  1.2  christos 
   1191  1.2  christos 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1192  1.1     lukem 
   1193  1.2  christos 				if ( age->age_filter && age->age_filter->agf_anlist ) {
   1194  1.2  christos 					ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
   1195  1.2  christos 				}
   1196  1.2  christos 				else {
   1197  1.2  christos 					ea = NULL;
   1198  1.2  christos 				}
   1199  1.1     lukem 
   1200  1.2  christos 				if ( age->age_modrdn_olddnmodified ) {
   1201  1.2  christos 					/* Resquest already marked this group to be updated */
   1202  1.2  christos 					is_olddn = 1;
   1203  1.2  christos 					is_value_refresh = 1;
   1204  1.2  christos 					age->age_modrdn_olddnmodified = 0;
   1205  1.2  christos 				} else {
   1206  1.2  christos 
   1207  1.2  christos 					if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
   1208  1.2  christos 						LDAP_SUCCESS || group == NULL ) {
   1209  1.2  christos 						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.2  christos 						op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
   1212  1.2  christos 						op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
   1213  1.1     lukem 
   1214  1.2  christos 						attrs_free( attrs );
   1215  1.2  christos 						ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1216  1.2  christos 						ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1217  1.2  christos 						return SLAP_CB_CONTINUE;
   1218  1.2  christos 					}
   1219  1.1     lukem 
   1220  1.2  christos 					a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
   1221  1.1     lukem 
   1222  1.2  christos 					if ( a != NULL ) {
   1223  1.2  christos 						if ( value_find_ex( age->age_def->agd_member_ad,
   1224  1.2  christos 								SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   1225  1.2  christos 								SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
   1226  1.2  christos 								a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
   1227  1.2  christos 						{
   1228  1.2  christos 							is_olddn = 1;
   1229  1.2  christos 						}
   1230  1.1     lukem 
   1231  1.1     lukem 					}
   1232  1.1     lukem 
   1233  1.2  christos 					overlay_entry_release_ov( op, group, 0, on );
   1234  1.2  christos 
   1235  1.1     lukem 				}
   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.2  christos 						/* 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.2  christos 				if ( is_value_refresh ) {
   1247  1.2  christos 					if ( is_olddn != is_newdn ) {
   1248  1.2  christos 						/* group refresh */
   1249  1.2  christos 						autogroup_delete_member_from_group( op, NULL, NULL, age) ;
   1250  1.2  christos 
   1251  1.2  christos 						for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1252  1.2  christos 							autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
   1253  1.2  christos 						}
   1254  1.2  christos 					}
   1255  1.2  christos 					ldap_pvt_thread_mutex_unlock( &age->age_mutex );
   1256  1.2  christos 					continue;
   1257  1.2  christos 				}
   1258  1.1     lukem 				if ( is_olddn == 1 && is_newdn == 0 ) {
   1259  1.2  christos 					if ( ea )
   1260  1.2  christos 						autogroup_delete_member_values_from_group( op, &new_dn, age, ea );
   1261  1.2  christos 					else
   1262  1.2  christos 						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.2  christos 					Entry etmp;
   1266  1.2  christos 					struct berval odn, ondn;
   1267  1.2  christos 					etmp.e_name = op->o_req_dn;
   1268  1.2  christos 					etmp.e_nname = op->o_req_ndn;
   1269  1.2  christos 					etmp.e_attrs = attrs;
   1270  1.2  christos 					odn = op->o_dn;
   1271  1.2  christos 					ondn = op->o_ndn;
   1272  1.2  christos 					op->o_dn = op->o_bd->be_rootdn;
   1273  1.2  christos 					op->o_ndn = op->o_bd->be_rootndn;
   1274  1.2  christos 
   1275  1.1     lukem 					for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
   1276  1.2  christos 						if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
   1277  1.2  christos 							if ( ea ) {
   1278  1.2  christos 								autogroup_add_member_values_to_group( op, &new_dn, age, ea );
   1279  1.2  christos 							} else
   1280  1.2  christos 								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.2  christos 					op->o_dn = odn;
   1285  1.2  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.2  christos 					if ( ea ) {
   1289  1.2  christos 						/* group refresh */
   1290  1.2  christos 						autogroup_delete_member_from_group( op, NULL, NULL, age) ;
   1291  1.2  christos 
   1292  1.2  christos 						for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1293  1.2  christos 							autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
   1294  1.2  christos 						}
   1295  1.2  christos 					}
   1296  1.2  christos 					else {
   1297  1.2  christos 						autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
   1298  1.2  christos 						autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
   1299  1.2  christos 					}
   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.2  christos 			attrs_free( attrs );
   1309  1.2  christos 
   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.2  christos 		if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS  && !oex ) {
   1316  1.2  christos 			Entry etmp;
   1317  1.2  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.2  christos 					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.2  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.2  christos 			attrs = attrs_dup( e->e_attrs );
   1401  1.2  christos 			overlay_entry_release_ov( op, e, 0, on );
   1402  1.2  christos 			etmp.e_name = op->o_req_dn;
   1403  1.2  christos 			etmp.e_nname = op->o_req_ndn;
   1404  1.2  christos 			etmp.e_attrs = attrs;
   1405  1.2  christos 			odn = op->o_dn;
   1406  1.2  christos 			ondn = op->o_ndn;
   1407  1.2  christos 			op->o_dn = op->o_bd->be_rootdn;
   1408  1.2  christos 			op->o_ndn = op->o_bd->be_rootndn;
   1409  1.2  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.2  christos 				ldap_pvt_thread_mutex_lock( &age->age_mutex );
   1415  1.1     lukem 
   1416  1.2  christos 				if ( age->age_filter && age->age_filter->agf_anlist ) {
   1417  1.2  christos 					ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
   1418  1.2  christos 				}
   1419  1.2  christos 				else {
   1420  1.2  christos 					ea = NULL;
   1421  1.2  christos 				}
   1422  1.1     lukem 
   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.2  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.2  christos 					op->o_dn = odn;
   1432  1.2  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.2  christos 							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.2  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.2  christos 					if(ea)
   1462  1.2  christos 						autogroup_delete_member_values_from_group( op, &op->o_req_dn, age, ea );
   1463  1.2  christos 					else
   1464  1.2  christos 						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.2  christos 					if(ea)
   1468  1.2  christos 						autogroup_add_member_values_to_group( op, &op->o_req_dn, age, ea );
   1469  1.2  christos 					else
   1470  1.2  christos 						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.2  christos 			op->o_dn = odn;
   1477  1.2  christos 			op->o_ndn = ondn;
   1478  1.2  christos 			attrs_free( attrs );
   1479  1.2  christos 
   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.2  christos ** Detect if filter contains a memberOf check for dn
   1489  1.2  christos */
   1490  1.2  christos static int
   1491  1.2  christos autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad )
   1492  1.2  christos {
   1493  1.2  christos 	int result = 0;
   1494  1.2  christos 	if ( f == NULL ) return 0;
   1495  1.2  christos 
   1496  1.2  christos   	switch ( f->f_choice & SLAPD_FILTER_MASK ) {
   1497  1.2  christos 		case LDAP_FILTER_AND:
   1498  1.2  christos 		case LDAP_FILTER_OR:
   1499  1.2  christos 		case LDAP_FILTER_NOT:
   1500  1.2  christos 			for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) {
   1501  1.2  christos 				result = result || autogroup_memberOf_filter( f, dn, memberof_ad );
   1502  1.2  christos 			}
   1503  1.2  christos 			break;
   1504  1.2  christos 		case LDAP_FILTER_EQUALITY:
   1505  1.2  christos 			result = ( f->f_ava->aa_desc == memberof_ad &&
   1506  1.2  christos 			           ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 );
   1507  1.2  christos 			break;
   1508  1.2  christos 		default:
   1509  1.2  christos 			break;
   1510  1.2  christos 	}
   1511  1.2  christos 
   1512  1.2  christos 	return result;
   1513  1.2  christos }
   1514  1.2  christos 
   1515  1.2  christos /*
   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.2  christos 	autogroup_entry_t	*age;
   1526  1.1     lukem 	Entry			*e;
   1527  1.1     lukem 	Attribute		*a;
   1528  1.2  christos 	struct berval odn, ondn;
   1529  1.2  christos 	OpExtra *oex;
   1530  1.1     lukem 
   1531  1.2  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
   1532  1.2  christos 		if ( oex->oe_key == (void *)&autogroup )
   1533  1.2  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.2  christos 	odn = op->o_dn;
   1547  1.2  christos 	ondn = op->o_ndn;
   1548  1.2  christos 	op->o_dn = op->o_bd->be_rootdn;
   1549  1.2  christos 	op->o_ndn = op->o_bd->be_rootndn;
   1550  1.2  christos 
   1551  1.2  christos 	/* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */
   1552  1.2  christos 	for ( age = agi->agi_entry; age ; age = age->age_next ) {
   1553  1.2  christos 		autogroup_filter_t	*agf;
   1554  1.2  christos 		for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1555  1.2  christos 			if ( agf->agf_anlist ) {
   1556  1.2  christos 				Modifications	*m;
   1557  1.2  christos 				for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
   1558  1.2  christos 					if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
   1559  1.2  christos 						if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
   1560  1.2  christos 							int rc = test_filter( op, e, agf->agf_filter );
   1561  1.2  christos 							if ( rc == LDAP_COMPARE_TRUE ) {
   1562  1.2  christos 								age->age_mustrefresh = 1;
   1563  1.2  christos 							}
   1564  1.2  christos 						}
   1565  1.2  christos 					}
   1566  1.2  christos 				}
   1567  1.2  christos 			}
   1568  1.2  christos 
   1569  1.2  christos 			if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) {
   1570  1.2  christos 				age->age_mustrefresh = 1;
   1571  1.2  christos 			}
   1572  1.2  christos 		}
   1573  1.2  christos 	}
   1574  1.2  christos 	op->o_dn = odn;
   1575  1.2  christos 	op->o_ndn = ondn;
   1576  1.2  christos 
   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.2  christos 			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.2  christos 			/* an entry may only have one dynamic group class */
   1617  1.2  christos 			break;
   1618  1.2  christos 		}
   1619  1.2  christos 	}
   1620  1.2  christos 
   1621  1.2  christos 	overlay_entry_release_ov( op, e, 0, on );
   1622  1.2  christos 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1623  1.2  christos 	return SLAP_CB_CONTINUE;
   1624  1.2  christos }
   1625  1.2  christos 
   1626  1.2  christos /*
   1627  1.2  christos ** Detect if the olddn is part of a group and so if the group should be refreshed
   1628  1.2  christos */
   1629  1.2  christos static int
   1630  1.2  christos autogroup_modrdn_entry( Operation *op, SlapReply *rs)
   1631  1.2  christos {
   1632  1.2  christos 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
   1633  1.2  christos 	autogroup_info_t	*agi = (autogroup_info_t *)on->on_bi.bi_private;
   1634  1.2  christos 	autogroup_entry_t	*age;
   1635  1.2  christos 	Entry			*e;
   1636  1.2  christos 	struct berval odn, ondn;
   1637  1.2  christos 	OpExtra *oex;
   1638  1.2  christos 
   1639  1.2  christos 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
   1640  1.2  christos 		if ( oex->oe_key == (void *)&autogroup )
   1641  1.1     lukem 			return SLAP_CB_CONTINUE;
   1642  1.2  christos 	}
   1643  1.2  christos 
   1644  1.2  christos 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1645  1.2  christos 	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
   1646  1.2  christos 
   1647  1.2  christos 	if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
   1648  1.2  christos 		LDAP_SUCCESS || e == NULL ) {
   1649  1.2  christos 		Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
   1650  1.2  christos 		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1651  1.2  christos 		return SLAP_CB_CONTINUE;
   1652  1.2  christos 	}
   1653  1.2  christos 
   1654  1.2  christos 	odn = op->o_dn;
   1655  1.2  christos 	ondn = op->o_ndn;
   1656  1.2  christos 	op->o_dn = op->o_bd->be_rootdn;
   1657  1.2  christos 	op->o_ndn = op->o_bd->be_rootndn;
   1658  1.2  christos 
   1659  1.2  christos 	/* Must check if a dn is modified */
   1660  1.2  christos 	for ( age = agi->agi_entry; age ; age = age->age_next ) {
   1661  1.2  christos 		autogroup_filter_t	*agf;
   1662  1.2  christos 		for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
   1663  1.2  christos 			if ( agf->agf_anlist ) {
   1664  1.2  christos 				if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
   1665  1.2  christos 					int rc = test_filter( op, e, agf->agf_filter );
   1666  1.2  christos 					if ( rc == LDAP_COMPARE_TRUE ) {
   1667  1.2  christos 						age->age_modrdn_olddnmodified = 1;
   1668  1.2  christos 					}
   1669  1.2  christos 				}
   1670  1.2  christos 			}
   1671  1.1     lukem 		}
   1672  1.1     lukem 	}
   1673  1.2  christos 	op->o_dn = odn;
   1674  1.2  christos 	op->o_ndn = ondn;
   1675  1.1     lukem 
   1676  1.1     lukem 	overlay_entry_release_ov( op, e, 0, on );
   1677  1.1     lukem 	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
   1678  1.1     lukem 	return SLAP_CB_CONTINUE;
   1679  1.1     lukem }
   1680  1.1     lukem 
   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.2  christos 	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.2  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.2  christos 
   1728  1.2  christos 	{ "autogroup-memberof-ad", "memberOf attribute",
   1729  1.2  christos 		2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen,
   1730  1.2  christos 		"( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' "
   1731  1.2  christos 			"DESC 'memberOf attribute' "
   1732  1.2  christos 			"SYNTAX OMsDirectoryString SINGLE-VALUE )",
   1733  1.2  christos 			NULL, NULL },
   1734  1.2  christos 
   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.2  christos 		"MAY ( "
   1744  1.2  christos 			"olcAGattrSet "
   1745  1.2  christos 			"$ olcAGmemberOfAd "
   1746  1.2  christos 		    ")"
   1747  1.2  christos 	  ")",
   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.2  christos 		switch( c->type ){
   1779  1.2  christos 		case AG_ATTRSET:
   1780  1.2  christos 			for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
   1781  1.2  christos 				struct berval	bv;
   1782  1.2  christos 				char		*ptr = c->cr_msg;
   1783  1.2  christos 
   1784  1.2  christos 				assert(agd->agd_oc != NULL);
   1785  1.2  christos 				assert(agd->agd_member_url_ad != NULL);
   1786  1.2  christos 				assert(agd->agd_member_ad != NULL);
   1787  1.2  christos 
   1788  1.2  christos 				ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
   1789  1.2  christos 					SLAP_X_ORDERED_FMT "%s %s %s", i,
   1790  1.2  christos 					agd->agd_oc->soc_cname.bv_val,
   1791  1.2  christos 					agd->agd_member_url_ad->ad_cname.bv_val,
   1792  1.2  christos 					agd->agd_member_ad->ad_cname.bv_val );
   1793  1.2  christos 
   1794  1.2  christos 				bv.bv_val = c->cr_msg;
   1795  1.2  christos 				bv.bv_len = ptr - bv.bv_val;
   1796  1.2  christos 				value_add_one ( &c->rvalue_vals, &bv );
   1797  1.2  christos 
   1798  1.2  christos 			}
   1799  1.2  christos 			break;
   1800  1.2  christos 
   1801  1.2  christos 		case AG_MEMBER_OF_AD:
   1802  1.2  christos 			if ( agi->agi_memberof_ad != NULL ){
   1803  1.2  christos 				value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname );
   1804  1.2  christos 			}
   1805  1.2  christos 			break;
   1806  1.1     lukem 
   1807  1.2  christos 		default:
   1808  1.2  christos 			assert( 0 );
   1809  1.2  christos 			return 1;
   1810  1.2  christos       }
   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.2  christos 					anlist_free( agf->agf_anlist, 1, NULL );
   1841  1.2  christos 					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.2  christos 						anlist_free( agf->agf_anlist, 1, NULL );
   1885  1.2  christos 						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.2  christos 		} break;
   2011  1.2  christos 
   2012  1.2  christos 	case AG_MEMBER_OF_AD: {
   2013  1.2  christos 		AttributeDescription *memberof_ad = NULL;
   2014  1.2  christos 		const char     *text;
   2015  1.2  christos 
   2016  1.2  christos 		rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text );
   2017  1.2  christos 		if( rc != LDAP_SUCCESS ) {
   2018  1.2  christos 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   2019  1.2  christos 				"\"autogroup-memberof-ad <memberof-ad>\": "
   2020  1.2  christos 				"unable to find AttributeDescription \"%s\"",
   2021  1.2  christos 				c->argv[ 1 ] );
   2022  1.2  christos 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   2023  1.2  christos 				c->log, c->cr_msg, 0 );
   2024  1.2  christos 			return 1;
   2025  1.2  christos 		}
   2026  1.2  christos 
   2027  1.2  christos 		if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX )    /* e.g. "member" */
   2028  1.2  christos 		     && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) )  /* e.g. "uniqueMember" */
   2029  1.2  christos 		{
   2030  1.2  christos 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   2031  1.2  christos 				"memberof attribute=\"%s\" must either "
   2032  1.2  christos 				"have DN (%s) or nameUID (%s) syntax",
   2033  1.2  christos 				c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
   2034  1.2  christos 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
   2035  1.2  christos 				c->log, c->cr_msg, 0 );
   2036  1.2  christos 			return 1;
   2037  1.2  christos 		}
   2038  1.2  christos 
   2039  1.2  christos 		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.2  christos extern int slapMode;
   2052  1.2  christos 
   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.2  christos 	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.2  christos 	if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
   2076  1.2  christos 		return 0;
   2077  1.2  christos 	}
   2078  1.2  christos 
   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.2  christos 	op->o_do_not_cache = 1;
   2097  1.2  christos 
   2098  1.2  christos 	op->o_bd = be;
   2099  1.2  christos 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
   2100  1.2  christos 
   2101  1.2  christos 	ags.ags_info = agi;
   2102  1.2  christos 	cb.sc_private = &ags;
   2103  1.2  christos 	cb.sc_response = autogroup_group_add_cb;
   2104  1.2  christos 	cb.sc_cleanup = NULL;
   2105  1.2  christos 	cb.sc_next = NULL;
   2106  1.1     lukem 
   2107  1.2  christos 	op->o_callback = &cb;
   2108  1.1     lukem 
   2109  1.1     lukem 	for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
   2110  1.2  christos 		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.2  christos 		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.2  christos 
   2122  1.2  christos 	if( ! agi->agi_memberof_ad ){
   2123  1.2  christos 		int			rc;
   2124  1.2  christos 		const char		*text = NULL;
   2125  1.2  christos 
   2126  1.2  christos 		rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text );
   2127  1.2  christos 		if ( rc != LDAP_SUCCESS ) {
   2128  1.2  christos 			Debug( LDAP_DEBUG_ANY, "autogroup_db_open: "
   2129  1.2  christos 			"unable to find attribute=\"%s\": %s (%d)\n",
   2130  1.2  christos 			SLAPD_MEMBEROF_ATTR, text, rc );
   2131  1.2  christos 			return rc;
   2132  1.2  christos 		}
   2133  1.2  christos 	}
   2134  1.1     lukem 
   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.2  christos 				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.2  christos 	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