1 /* autogroup.c - automatic group overlay */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2007-2015 The OpenLDAP Foundation.
6 * Portions Copyright 2007 Michał Szulczyński.
7 * Portions Copyright 2009 Howard Chu.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
19 * This work was initially developed by Michał Szulczyński for inclusion in
20 * OpenLDAP Software. Additional significant contributors include:
31 #include <ac/string.h>
37 #ifndef SLAPD_MEMBEROF_ATTR
38 #define SLAPD_MEMBEROF_ATTR "memberOf"
41 /* Filter represents the memberURL of a group. */
42 typedef struct autogroup_filter_t {
43 struct berval agf_dn; /* The base DN in memberURL */
44 struct berval agf_ndn;
45 struct berval agf_filterstr;
48 AttributeName *agf_anlist;
49 struct autogroup_filter_t *agf_next;
52 /* Description of group attributes. */
53 typedef struct autogroup_def_t {
55 AttributeDescription *agd_member_url_ad;
56 AttributeDescription *agd_member_ad;
57 struct autogroup_def_t *agd_next;
60 /* Represents the group entry. */
61 typedef struct autogroup_entry_t {
64 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
65 autogroup_def_t *age_def; /* Attribute definition */
66 ldap_pvt_thread_mutex_t age_mutex;
67 int age_mustrefresh; /* Defined in request to refresh in response */
68 int age_modrdn_olddnmodified; /* Defined in request to refresh in response */
69 struct autogroup_entry_t *age_next;
72 /* Holds pointers to attribute definitions and groups. */
73 typedef struct autogroup_info_t {
74 autogroup_def_t *agi_def; /* Group attributes definitions. */
75 autogroup_entry_t *agi_entry; /* Group entries. */
76 AttributeDescription *agi_memberof_ad; /* memberOf attribute description */
77 ldap_pvt_thread_mutex_t agi_mutex;
80 /* Search callback for adding groups initially. */
81 typedef struct autogroup_sc_t {
82 autogroup_info_t *ags_info; /* Group definitions and entries. */
83 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
86 /* Used for adding members, found when searching, to a group. */
87 typedef struct autogroup_ga_t {
88 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
89 autogroup_filter_t *agg_filter; /* Current filter */
90 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
91 this entry with the search results. */
93 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
94 search results which will be added to the group. */
96 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
97 have to search for the last mod added. */
102 ** dn, ndn - the DN of the member to add
103 ** age - the group to which the member DN will be added
106 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
108 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
109 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
110 SlapReply sreply = {REP_RESULT};
111 BerValue *vals, *nvals;
112 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
114 unsigned long opid = op->o_opid;
116 assert( dn != NULL );
117 assert( ndn != NULL );
118 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
119 dn->bv_val, age->age_dn.bv_val, 0);
121 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
122 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
123 ber_dupbv( vals, dn );
124 BER_BVZERO( &vals[ 1 ] );
125 ber_dupbv( nvals, ndn );
126 BER_BVZERO( &nvals[ 1 ] );
128 modlist->sml_op = LDAP_MOD_ADD;
129 modlist->sml_desc = age->age_def->agd_member_ad;
130 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
131 modlist->sml_values = vals;
132 modlist->sml_nvalues = nvals;
133 modlist->sml_numvals = 1;
134 modlist->sml_flags = SLAP_MOD_INTERNAL;
135 modlist->sml_next = NULL;
137 o.o_opid = 0; /* shared with op, saved above */
138 o.o_tag = LDAP_REQ_MODIFY;
140 o.orm_modlist = modlist;
141 o.o_dn = op->o_bd->be_rootdn;
142 o.o_ndn = op->o_bd->be_rootndn;
143 o.o_req_dn = age->age_dn;
144 o.o_req_ndn = age->age_ndn;
145 o.o_permissive_modify = 1;
146 o.o_dont_replicate = 1;
147 o.orm_no_opattrs = 1;
148 o.o_managedsait = SLAP_CONTROL_CRITICAL;
149 o.o_relax = SLAP_CONTROL_CRITICAL;
151 o.o_bd->bd_info = (BackendInfo *)on->on_info;
152 (void)op->o_bd->be_modify( &o, &sreply );
153 o.o_bd->bd_info = (BackendInfo *)on;
155 slap_mods_free( modlist, 1 );
158 return sreply.sr_err;
162 ** e - the entry where to get the attribute values
163 ** age - the group to which the values will be added
166 autogroup_add_member_values_to_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
168 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
169 Modifications modlist;
170 SlapReply sreply = {REP_RESULT};
171 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
173 unsigned long opid = op->o_opid;
175 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
176 dn->bv_val, age->age_dn.bv_val, 0);
178 modlist.sml_op = LDAP_MOD_ADD;
179 modlist.sml_desc = age->age_def->agd_member_ad;
180 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
181 modlist.sml_values = attr->a_vals;
182 modlist.sml_nvalues = attr->a_nvals;
183 modlist.sml_numvals = attr->a_numvals;
184 modlist.sml_flags = SLAP_MOD_INTERNAL;
185 modlist.sml_next = NULL;
188 o.o_tag = LDAP_REQ_MODIFY;
190 o.orm_modlist = &modlist;
191 o.o_dn = op->o_bd->be_rootdn;
192 o.o_ndn = op->o_bd->be_rootndn;
193 o.o_req_dn = age->age_dn;
194 o.o_req_ndn = age->age_ndn;
195 o.o_permissive_modify = 1;
196 o.o_dont_replicate = 1;
197 o.orm_no_opattrs = 1;
198 o.o_managedsait = SLAP_CONTROL_CRITICAL;
199 o.o_relax = SLAP_CONTROL_CRITICAL;
201 o.o_bd->bd_info = (BackendInfo *)on->on_info;
202 (void)op->o_bd->be_modify( &o, &sreply );
203 o.o_bd->bd_info = (BackendInfo *)on;
206 return sreply.sr_err;
210 ** dn,ndn - the DN to be deleted
211 ** age - the group from which the DN will be deleted
212 ** If we pass a NULL dn and ndn, all members are deleted from the group.
215 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
217 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
218 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
219 SlapReply sreply = {REP_RESULT};
220 BerValue *vals, *nvals;
221 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
223 unsigned long opid = op->o_opid;
225 if ( dn == NULL || ndn == NULL ) {
226 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
227 age->age_dn.bv_val, 0 ,0);
229 modlist->sml_values = NULL;
230 modlist->sml_nvalues = NULL;
231 modlist->sml_numvals = 0;
233 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
234 dn->bv_val, age->age_dn.bv_val, 0);
236 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
237 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
238 ber_dupbv( vals, dn );
239 BER_BVZERO( &vals[ 1 ] );
240 ber_dupbv( nvals, ndn );
241 BER_BVZERO( &nvals[ 1 ] );
243 modlist->sml_values = vals;
244 modlist->sml_nvalues = nvals;
245 modlist->sml_numvals = 1;
249 modlist->sml_op = LDAP_MOD_DELETE;
250 modlist->sml_desc = age->age_def->agd_member_ad;
251 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
252 modlist->sml_flags = SLAP_MOD_INTERNAL;
253 modlist->sml_next = NULL;
257 o.o_tag = LDAP_REQ_MODIFY;
258 o.orm_modlist = modlist;
259 o.o_dn = op->o_bd->be_rootdn;
260 o.o_ndn = op->o_bd->be_rootndn;
261 o.o_req_dn = age->age_dn;
262 o.o_req_ndn = age->age_ndn;
263 o.o_relax = SLAP_CONTROL_CRITICAL;
264 o.o_managedsait = SLAP_CONTROL_CRITICAL;
265 o.o_permissive_modify = 1;
266 o.o_dont_replicate = 1;
267 o.orm_no_opattrs = 1;
269 o.o_bd->bd_info = (BackendInfo *)on->on_info;
270 (void)op->o_bd->be_modify( &o, &sreply );
271 o.o_bd->bd_info = (BackendInfo *)on;
273 slap_mods_free( modlist, 1 );
276 return sreply.sr_err;
280 ** e - the entry where to get the attribute values
281 ** age - the group from which the values will be deleted
284 autogroup_delete_member_values_from_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
286 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
287 Modifications modlist;
288 SlapReply sreply = {REP_RESULT};
289 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
291 unsigned long opid = op->o_opid;
293 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n",
294 dn->bv_val, age->age_dn.bv_val, 0);
296 modlist.sml_op = LDAP_MOD_DELETE;
297 modlist.sml_desc = age->age_def->agd_member_ad;
298 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
299 modlist.sml_values = attr->a_vals;
300 modlist.sml_nvalues = attr->a_nvals;
301 modlist.sml_numvals = attr->a_numvals;
302 modlist.sml_flags = SLAP_MOD_INTERNAL;
303 modlist.sml_next = NULL;
306 o.o_tag = LDAP_REQ_MODIFY;
308 o.orm_modlist = &modlist;
309 o.o_dn = op->o_bd->be_rootdn;
310 o.o_ndn = op->o_bd->be_rootndn;
311 o.o_req_dn = age->age_dn;
312 o.o_req_ndn = age->age_ndn;
313 o.o_permissive_modify = 1;
314 o.o_dont_replicate = 1;
315 o.orm_no_opattrs = 1;
316 o.o_managedsait = SLAP_CONTROL_CRITICAL;
317 o.o_relax = SLAP_CONTROL_CRITICAL;
319 o.o_bd->bd_info = (BackendInfo *)on->on_info;
320 (void)op->o_bd->be_modify( &o, &sreply );
321 o.o_bd->bd_info = (BackendInfo *)on;
324 return sreply.sr_err;
328 ** Callback used to add entries to a group,
329 ** which are going to be written in the database
330 ** (used in bi_op_add)
331 ** The group is passed in autogroup_ga_t->agg_group
334 autogroup_member_search_cb( Operation *op, SlapReply *rs )
336 assert( op->o_tag == LDAP_REQ_SEARCH );
338 if ( rs->sr_type == REP_SEARCH ) {
339 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
340 autogroup_entry_t *age = agg->agg_group;
341 autogroup_filter_t *agf = agg->agg_filter;
343 const char *text = NULL;
345 struct berval *vals, *nvals;
346 struct berval lvals[ 2 ], lnvals[ 2 ];
349 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
350 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
352 if ( agf->agf_anlist ) {
353 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
356 nvals = attr->a_nvals;
357 numvals = attr->a_numvals;
363 lvals[ 0 ] = rs->sr_entry->e_name;
364 BER_BVZERO( &lvals[ 1 ] );
365 lnvals[ 0 ] = rs->sr_entry->e_nname;
366 BER_BVZERO( &lnvals[ 1 ] );
372 mod.sm_op = LDAP_MOD_ADD;
373 mod.sm_desc = age->age_def->agd_member_ad;
374 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
375 mod.sm_values = vals;
376 mod.sm_nvalues = nvals;
377 mod.sm_numvals = numvals;
379 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
386 ** Callback used to add entries to a group, which is already in the database.
387 ** (used in on_response)
388 ** The group is passed in autogroup_ga_t->agg_group
392 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
394 assert( op->o_tag == LDAP_REQ_SEARCH );
396 if ( rs->sr_type == REP_SEARCH ) {
397 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
398 autogroup_entry_t *age = agg->agg_group;
399 autogroup_filter_t *agf = agg->agg_filter;
400 Modifications *modlist;
401 struct berval *vals, *nvals;
402 struct berval lvals[ 2 ], lnvals[ 2 ];
405 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
406 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
408 if ( agf->agf_anlist ) {
409 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
412 nvals = attr->a_nvals;
413 numvals = attr->a_numvals;
419 lvals[ 0 ] = rs->sr_entry->e_name;
420 BER_BVZERO( &lvals[ 1 ] );
421 lnvals[ 0 ] = rs->sr_entry->e_nname;
422 BER_BVZERO( &lnvals[ 1 ] );
429 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
431 modlist->sml_op = LDAP_MOD_ADD;
432 modlist->sml_desc = age->age_def->agd_member_ad;
433 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
435 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
436 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
437 modlist->sml_numvals = numvals;
439 modlist->sml_flags = SLAP_MOD_INTERNAL;
440 modlist->sml_next = NULL;
442 if ( agg->agg_mod == NULL ) {
443 agg->agg_mod = modlist;
444 agg->agg_mod_last = modlist;
446 agg->agg_mod_last->sml_next = modlist;
447 agg->agg_mod_last = modlist;
458 ** Adds all entries matching the passed filter to the specified group.
459 ** If modify == 1, then we modify the group's entry in the database using be_modify.
460 ** If modify == 0, then, we must supply a rw entry for the group,
461 ** because we only modify the entry, without calling be_modify.
462 ** e - the group entry, to which the members will be added
467 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
469 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
471 SlapReply rs = { REP_SEARCH };
472 slap_callback cb = { 0 };
473 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
476 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
477 age->age_dn.bv_val, 0, 0);
480 o.o_tag = LDAP_REQ_SEARCH;
482 o.o_dn = op->o_bd->be_rootdn;
483 o.o_ndn = op->o_bd->be_rootndn;
484 o.o_req_dn = agf->agf_dn;
485 o.o_req_ndn = agf->agf_ndn;
487 o.ors_filterstr = agf->agf_filterstr;
488 o.ors_filter = agf->agf_filter;
490 o.ors_scope = agf->agf_scope;
491 o.ors_deref = LDAP_DEREF_NEVER;
493 o.ors_tlimit = SLAP_NO_LIMIT;
494 o.ors_slimit = SLAP_NO_LIMIT;
495 o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
496 o.o_do_not_cache = 1;
499 agg.agg_filter = agf;
501 agg.agg_mod_last = NULL;
503 cb.sc_private = &agg;
506 cb.sc_response = autogroup_member_search_modify_cb;
508 cb.sc_response = autogroup_member_search_cb;
511 cb.sc_cleanup = NULL;
516 o.o_bd->bd_info = (BackendInfo *)on->on_info;
517 op->o_bd->be_search( &o, &rs );
518 o.o_bd->bd_info = (BackendInfo *)on;
520 if ( modify == 1 && agg.agg_mod ) {
521 unsigned long opid = op->o_opid;
523 rs_reinit( &rs, REP_RESULT );
527 o.o_callback = &null_cb;
528 o.o_tag = LDAP_REQ_MODIFY;
529 o.orm_modlist = agg.agg_mod;
530 o.o_dn = op->o_bd->be_rootdn;
531 o.o_ndn = op->o_bd->be_rootndn;
532 o.o_req_dn = age->age_dn;
533 o.o_req_ndn = age->age_ndn;
534 o.o_relax = SLAP_CONTROL_CRITICAL;
535 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
536 o.o_permissive_modify = 1;
537 o.o_dont_replicate = 1;
538 o.orm_no_opattrs = 1;
540 o.o_bd->bd_info = (BackendInfo *)on->on_info;
541 (void)op->o_bd->be_modify( &o, &rs );
542 o.o_bd->bd_info = (BackendInfo *)on;
544 slap_mods_free(agg.agg_mod, 1);
552 ** Adds a group to the internal list from the passed entry.
553 ** scan specifies whether to add all maching members to the group.
554 ** modify specifies whether to modify the given group entry (when modify == 0),
555 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
556 ** agi - pointer to the groups and the attribute definitions
557 ** agd - the attribute definition of the added group
558 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
559 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
562 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
564 autogroup_entry_t **agep = &agi->agi_entry;
565 autogroup_filter_t *agf, *agf_prev = NULL;
566 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
567 LDAPURLDesc *lud = NULL;
570 int rc = 0, match = 1, null_entry = 0;
573 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
574 LDAP_SUCCESS || e == NULL ) {
575 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
582 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
583 e->e_name.bv_val, 0, 0);
585 if ( agi->agi_entry != NULL ) {
586 for ( ; *agep ; agep = &(*agep)->age_next ) {
587 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
589 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
597 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
598 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
599 (*agep)->age_def = agd;
600 (*agep)->age_filter = NULL;
601 (*agep)->age_mustrefresh = 0;
602 (*agep)->age_modrdn_olddnmodified = 0;
604 ber_dupbv( &(*agep)->age_dn, &e->e_name );
605 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
607 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
609 if ( null_entry == 1 ) {
611 overlay_entry_release_ov( op, e, 0, on );
615 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
617 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
619 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
621 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
622 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
628 agf->agf_scope = lud->lud_scope;
630 if ( lud->lud_dn == NULL ) {
631 BER_BVSTR( &dn, "" );
633 ber_str2bv( lud->lud_dn, 0, 0, &dn );
636 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
637 if ( rc != LDAP_SUCCESS ) {
638 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
643 if ( lud->lud_filter != NULL ) {
644 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
645 agf->agf_filter = str2filter( lud->lud_filter );
647 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: URL filter is missing <%s>\n", bv->bv_val,0,0);
652 if ( lud->lud_attrs != NULL ) {
655 for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
660 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n",
663 filter_free( agf->agf_filter );
664 ch_free( agf->agf_filterstr.bv_val );
665 ch_free( agf->agf_dn.bv_val );
666 ch_free( agf->agf_ndn.bv_val );
667 ldap_free_urldesc( lud );
672 agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
674 if ( agf->agf_anlist == NULL ) {
675 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
676 lud->lud_attrs[0], 0, 0 );
678 filter_free( agf->agf_filter );
679 ch_free( agf->agf_filterstr.bv_val );
680 ch_free( agf->agf_dn.bv_val );
681 ch_free( agf->agf_ndn.bv_val );
682 ldap_free_urldesc( lud );
688 agf->agf_next = NULL;
690 if( (*agep)->age_filter == NULL ) {
691 (*agep)->age_filter = agf;
694 if( agf_prev != NULL ) {
695 agf_prev->agf_next = agf;
701 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
704 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
705 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
707 ldap_free_urldesc( lud );
714 ch_free( agf->agf_ndn.bv_val );
715 ch_free( agf->agf_dn.bv_val );
716 ldap_free_urldesc( lud );
721 if ( null_entry == 1 ) {
728 ** Used when opening the database to add all existing
729 ** groups from the database to our internal list.
732 autogroup_group_add_cb( Operation *op, SlapReply *rs )
734 assert( op->o_tag == LDAP_REQ_SEARCH );
736 if ( rs->sr_type == REP_SEARCH ) {
737 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
739 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
740 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
742 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
748 typedef struct ag_addinfo {
751 autogroup_def_t *agd;
755 autogroup_add_entry_cb( Operation *op, SlapReply *rs )
757 slap_callback *sc = op->o_callback;
758 ag_addinfo *aa = sc->sc_private;
759 slap_overinst *on = aa->on;
760 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
761 BackendInfo *bi = op->o_bd->bd_info;
763 if ( rs->sr_err != LDAP_SUCCESS )
766 op->o_bd->bd_info = (BackendInfo *)on;
767 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
769 autogroup_add_group( op, agi, aa->agd, aa->e, NULL, 1 , 0);
771 autogroup_entry_t *age;
772 autogroup_filter_t *agf;
773 struct berval odn, ondn;
776 /* must use rootdn when calling test_filter */
779 op->o_dn = op->o_bd->be_rootdn;
780 op->o_ndn = op->o_bd->be_rootndn;
782 for ( age = agi->agi_entry; age ; age = age->age_next ) {
783 ldap_pvt_thread_mutex_lock( &age->age_mutex );
785 /* Check if any of the filters are the suffix to the entry DN.
786 If yes, we can test that filter against the entry. */
788 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
789 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
790 rc = test_filter( op, aa->e, agf->agf_filter );
791 if ( rc == LDAP_COMPARE_TRUE ) {
792 if ( agf->agf_anlist ) {
793 Attribute *a = attr_find( aa->e->e_attrs, agf->agf_anlist[0].an_desc );
795 autogroup_add_member_values_to_group( op, &op->o_req_dn, age, a );
797 autogroup_add_member_to_group( op, &aa->e->e_name, &aa->e->e_nname, age );
803 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
808 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
810 op->o_bd->bd_info = bi;
813 op->o_callback = sc->sc_next;
814 op->o_tmpfree( sc, op->o_tmpmemctx );
816 return SLAP_CB_CONTINUE;
820 ** When adding a group, we first strip any existing members,
821 ** and add all which match the filters ourselfs.
824 autogroup_add_entry( Operation *op, SlapReply *rs)
826 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
827 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
828 autogroup_def_t *agd = agi->agi_def;
829 slap_callback *sc = NULL;
830 ag_addinfo *aa = NULL;
833 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
834 op->ora_e->e_name.bv_val, 0, 0);
836 sc = op->o_tmpcalloc( sizeof(slap_callback) + sizeof(ag_addinfo), 1, op->o_tmpmemctx );
837 sc->sc_private = (sc+1);
838 sc->sc_response = autogroup_add_entry_cb;
842 sc->sc_next = op->o_callback;
845 /* Check if it's a group. */
846 for ( ; agd ; agd = agd->agd_next ) {
847 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
849 const char *text = NULL;
852 mod.sm_op = LDAP_MOD_DELETE;
853 mod.sm_desc = agd->agd_member_ad;
854 mod.sm_type = agd->agd_member_ad->ad_cname;
855 mod.sm_values = NULL;
856 mod.sm_nvalues = NULL;
858 /* We don't want any member attributes added by the user. */
859 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
867 return SLAP_CB_CONTINUE;
871 ** agi - internal group and attribute definitions list
872 ** e - the group to remove from the internal list
875 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
877 autogroup_entry_t *age = agi->agi_entry,
882 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
883 age->age_dn.bv_val, 0, 0);
885 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
886 age_next = age->age_next;
889 autogroup_filter_t *agf = age->age_filter,
892 if ( age_prev != NULL ) {
893 age_prev->age_next = age_next;
895 agi->agi_entry = NULL;
898 ch_free( age->age_dn.bv_val );
899 ch_free( age->age_ndn.bv_val );
901 for( agf_next = agf ; agf_next ; agf = agf_next ){
902 agf_next = agf->agf_next;
904 filter_free( agf->agf_filter );
905 ch_free( agf->agf_filterstr.bv_val );
906 ch_free( agf->agf_dn.bv_val );
907 ch_free( agf->agf_ndn.bv_val );
908 anlist_free( agf->agf_anlist, 1, NULL );
912 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
913 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
922 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
929 autogroup_delete_entry( Operation *op, SlapReply *rs)
931 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
932 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
933 autogroup_entry_t *age, *age_prev, *age_next;
934 autogroup_filter_t *agf;
936 int matched_group = 0, rc = 0;
937 struct berval odn, ondn;
939 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
941 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
943 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
944 LDAP_SUCCESS || e == NULL ) {
945 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
946 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
947 return SLAP_CB_CONTINUE;
950 /* Check if the entry to be deleted is one of our groups. */
951 for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) {
953 ldap_pvt_thread_mutex_lock( &age->age_mutex );
954 age_next = age->age_next;
956 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
961 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
964 autogroup_delete_group( agi, age );
969 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
972 if ( matched_group == 1 ) {
973 overlay_entry_release_ov( op, e, 0, on );
974 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
975 return SLAP_CB_CONTINUE;
978 /* Check if the entry matches any of the groups.
979 If yes, we can delete the entry from that group. */
983 op->o_dn = op->o_bd->be_rootdn;
984 op->o_ndn = op->o_bd->be_rootndn;
986 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
987 ldap_pvt_thread_mutex_lock( &age->age_mutex );
989 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
990 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
991 rc = test_filter( op, e, agf->agf_filter );
992 if ( rc == LDAP_COMPARE_TRUE ) {
993 /* If the attribute is retrieved from the entry, we don't know what to delete
994 ** So the group must be entirely refreshed
995 ** But the refresh can't be done now because the entry is not deleted
996 ** So the group is marked as mustrefresh
998 if ( agf->agf_anlist ) {
999 age->age_mustrefresh = 1;
1001 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
1007 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1012 overlay_entry_release_ov( op, e, 0, on );
1013 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1015 return SLAP_CB_CONTINUE;
1019 autogroup_response( Operation *op, SlapReply *rs )
1021 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1022 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1023 autogroup_def_t *agd = agi->agi_def;
1024 autogroup_entry_t *age;
1025 autogroup_filter_t *agf;
1026 BerValue new_dn, new_ndn, pdn;
1028 Attribute *a, *ea, *attrs;
1029 int is_olddn, is_newdn, is_value_refresh, dn_equal;
1031 /* Handle all cases where a refresh of the group is needed */
1032 if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
1033 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
1035 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1037 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1038 /* Request detected that the group must be refreshed */
1040 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1042 if ( age->age_mustrefresh ) {
1043 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1045 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1046 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1050 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1053 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1055 } else if ( op->o_tag == LDAP_REQ_MODRDN ) {
1056 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
1058 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
1060 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1062 if ( op->oq_modrdn.rs_newSup ) {
1063 pdn = *op->oq_modrdn.rs_newSup;
1065 dnParent( &op->o_req_dn, &pdn );
1067 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
1069 if ( op->oq_modrdn.rs_nnewSup ) {
1070 pdn = *op->oq_modrdn.rs_nnewSup;
1072 dnParent( &op->o_req_ndn, &pdn );
1074 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
1076 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
1078 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
1080 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
1081 LDAP_SUCCESS || e == NULL ) {
1082 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
1083 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1084 return SLAP_CB_CONTINUE;
1087 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1091 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
1092 overlay_entry_release_ov( op, e, 0, on );
1093 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1094 return SLAP_CB_CONTINUE;
1098 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
1099 for ( ; agd; agd = agd->agd_next ) {
1101 if ( value_find_ex( slap_schema.si_ad_objectClass,
1102 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1103 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1104 a->a_nvals, &agd->agd_oc->soc_cname,
1105 op->o_tmpmemctx ) == 0 )
1107 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1110 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
1112 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
1113 ber_dupbv( &age->age_dn, &new_dn );
1114 ber_dupbv( &age->age_ndn, &new_ndn );
1116 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1117 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1118 overlay_entry_release_ov( op, e, 0, on );
1119 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1120 return SLAP_CB_CONTINUE;
1128 1. check if the orginal entry's DN is in the group.
1129 2. chceck if the any of the group filter's base DN is a suffix of the new DN
1131 If 1 and 2 are both false, we do nothing.
1132 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
1133 If 1 is false, and 2 is true, we check the entry against the group's filters,
1134 and add it's DN to the group.
1135 If 1 is true, and 2 is false, we delete the entry's DN from the group.
1137 attrs = attrs_dup( e->e_attrs );
1138 overlay_entry_release_ov( op, e, 0, on );
1139 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1142 is_value_refresh = 0;
1144 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1146 if ( age->age_filter && age->age_filter->agf_anlist ) {
1147 ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
1153 if ( age->age_modrdn_olddnmodified ) {
1154 /* Resquest already marked this group to be updated */
1156 is_value_refresh = 1;
1157 age->age_modrdn_olddnmodified = 0;
1160 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1161 LDAP_SUCCESS || group == NULL ) {
1162 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
1164 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1165 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1167 attrs_free( attrs );
1168 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1169 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1170 return SLAP_CB_CONTINUE;
1173 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1176 if ( value_find_ex( age->age_def->agd_member_ad,
1177 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1178 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1179 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1186 overlay_entry_release_ov( op, group, 0, on );
1190 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1191 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
1192 /* TODO: should retest filter as it could imply conditions on the dn */
1199 if ( is_value_refresh ) {
1200 if ( is_olddn != is_newdn ) {
1202 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1204 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1205 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1208 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1211 if ( is_olddn == 1 && is_newdn == 0 ) {
1213 autogroup_delete_member_values_from_group( op, &new_dn, age, ea );
1215 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1217 if ( is_olddn == 0 && is_newdn == 1 ) {
1219 struct berval odn, ondn;
1220 etmp.e_name = op->o_req_dn;
1221 etmp.e_nname = op->o_req_ndn;
1222 etmp.e_attrs = attrs;
1225 op->o_dn = op->o_bd->be_rootdn;
1226 op->o_ndn = op->o_bd->be_rootndn;
1228 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
1229 if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1231 autogroup_add_member_values_to_group( op, &new_dn, age, ea );
1233 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1240 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
1243 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1245 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1246 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1250 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1251 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1255 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1258 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1259 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1261 attrs_free( attrs );
1263 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1267 if ( op->o_tag == LDAP_REQ_MODIFY ) {
1268 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
1270 struct berval odn, ondn;
1271 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
1273 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1275 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1276 LDAP_SUCCESS || e == NULL ) {
1277 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1278 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1279 return SLAP_CB_CONTINUE;
1282 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1286 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1287 overlay_entry_release_ov( op, e, 0, on );
1288 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1289 return SLAP_CB_CONTINUE;
1292 /* If we modify a group's memberURL, we have to delete all of it's members,
1293 and add them anew, because we cannot tell from which memberURL a member was added. */
1294 for ( ; agd; agd = agd->agd_next ) {
1296 if ( value_find_ex( slap_schema.si_ad_objectClass,
1297 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1298 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1299 a->a_nvals, &agd->agd_oc->soc_cname,
1300 op->o_tmpmemctx ) == 0 )
1305 m = op->orm_modlist;
1307 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1308 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1310 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1313 for ( ; m ; m = m->sml_next ) {
1314 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
1315 autogroup_def_t *group_agd = age->age_def;
1316 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
1317 op->o_req_dn.bv_val, 0, 0);
1319 overlay_entry_release_ov( op, e, 0, on );
1321 autogroup_delete_member_from_group( op, NULL, NULL, age );
1322 autogroup_delete_group( agi, age );
1324 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
1326 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1327 return SLAP_CB_CONTINUE;
1331 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1335 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1338 overlay_entry_release_ov( op, e, 0, on );
1339 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1340 return SLAP_CB_CONTINUE;
1344 /* When modifying any of the attributes of an entry, we must
1345 check if the entry is in any of our groups, and if
1346 the modified entry maches any of the filters of that group.
1348 If the entry exists in a group, but the modified attributes do
1349 not match any of the group's filters, we delete the entry from that group.
1350 If the entry doesn't exist in a group, but matches a filter,
1351 we add it to that group.
1353 attrs = attrs_dup( e->e_attrs );
1354 overlay_entry_release_ov( op, e, 0, on );
1355 etmp.e_name = op->o_req_dn;
1356 etmp.e_nname = op->o_req_ndn;
1357 etmp.e_attrs = attrs;
1360 op->o_dn = op->o_bd->be_rootdn;
1361 op->o_ndn = op->o_bd->be_rootndn;
1363 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1367 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1369 if ( age->age_filter && age->age_filter->agf_anlist ) {
1370 ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
1376 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1377 LDAP_SUCCESS || group == NULL ) {
1378 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
1379 age->age_dn.bv_val, 0, 0);
1381 attrs_free( attrs );
1382 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1383 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1386 return SLAP_CB_CONTINUE;
1389 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1392 if ( value_find_ex( age->age_def->agd_member_ad,
1393 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1394 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1395 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1402 overlay_entry_release_ov( op, group, 0, on );
1404 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1405 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1406 if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1413 if ( is_olddn == 1 && is_newdn == 0 ) {
1415 autogroup_delete_member_values_from_group( op, &op->o_req_dn, age, ea );
1417 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1419 if ( is_olddn == 0 && is_newdn == 1 ) {
1421 autogroup_add_member_values_to_group( op, &op->o_req_dn, age, ea );
1423 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1426 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1431 attrs_free( attrs );
1433 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1437 return SLAP_CB_CONTINUE;
1441 ** Detect if filter contains a memberOf check for dn
1444 autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad )
1447 if ( f == NULL ) return 0;
1449 switch ( f->f_choice & SLAPD_FILTER_MASK ) {
1450 case LDAP_FILTER_AND:
1451 case LDAP_FILTER_OR:
1452 case LDAP_FILTER_NOT:
1453 for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) {
1454 result = result || autogroup_memberOf_filter( f, dn, memberof_ad );
1457 case LDAP_FILTER_EQUALITY:
1458 result = ( f->f_ava->aa_desc == memberof_ad &&
1459 ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 );
1469 ** When modifing a group, we must deny any modifications to the member attribute,
1470 ** because the group would be inconsistent.
1473 autogroup_modify_entry( Operation *op, SlapReply *rs)
1475 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1476 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1477 autogroup_def_t *agd = agi->agi_def;
1478 autogroup_entry_t *age;
1481 struct berval odn, ondn;
1483 if ( get_manageDSAit( op ) ) {
1484 return SLAP_CB_CONTINUE;
1487 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1488 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1490 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1491 LDAP_SUCCESS || e == NULL ) {
1492 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1493 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1494 return SLAP_CB_CONTINUE;
1499 op->o_dn = op->o_bd->be_rootdn;
1500 op->o_ndn = op->o_bd->be_rootndn;
1502 /* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */
1503 for ( age = agi->agi_entry; age ; age = age->age_next ) {
1504 autogroup_filter_t *agf;
1505 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1506 if ( agf->agf_anlist ) {
1508 for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
1509 if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
1510 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1511 int rc = test_filter( op, e, agf->agf_filter );
1512 if ( rc == LDAP_COMPARE_TRUE ) {
1513 age->age_mustrefresh = 1;
1520 if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) {
1521 age->age_mustrefresh = 1;
1528 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1531 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1532 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1533 return SLAP_CB_CONTINUE;
1537 for ( ; agd; agd = agd->agd_next ) {
1539 if ( value_find_ex( slap_schema.si_ad_objectClass,
1540 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1541 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1542 a->a_nvals, &agd->agd_oc->soc_cname,
1543 op->o_tmpmemctx ) == 0 )
1548 m = op->orm_modlist;
1550 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1551 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1554 for ( ; m ; m = m->sml_next ) {
1555 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1556 overlay_entry_release_ov( op, e, 0, on );
1557 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1558 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1559 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1560 return LDAP_CONSTRAINT_VIOLATION;
1567 overlay_entry_release_ov( op, e, 0, on );
1568 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1569 return SLAP_CB_CONTINUE;
1573 overlay_entry_release_ov( op, e, 0, on );
1574 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1575 return SLAP_CB_CONTINUE;
1579 ** Detect if the olddn is part of a group and so if the group should be refreshed
1582 autogroup_modrdn_entry( Operation *op, SlapReply *rs)
1584 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1585 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1586 autogroup_entry_t *age;
1588 struct berval odn, ondn;
1590 if ( get_manageDSAit( op ) ) {
1591 return SLAP_CB_CONTINUE;
1594 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1595 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1597 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1598 LDAP_SUCCESS || e == NULL ) {
1599 Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1600 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1601 return SLAP_CB_CONTINUE;
1606 op->o_dn = op->o_bd->be_rootdn;
1607 op->o_ndn = op->o_bd->be_rootndn;
1609 /* Must check if a dn is modified */
1610 for ( age = agi->agi_entry; age ; age = age->age_next ) {
1611 autogroup_filter_t *agf;
1612 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1613 if ( agf->agf_anlist ) {
1614 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1615 int rc = test_filter( op, e, agf->agf_filter );
1616 if ( rc == LDAP_COMPARE_TRUE ) {
1617 age->age_modrdn_olddnmodified = 1;
1626 overlay_entry_release_ov( op, e, 0, on );
1627 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1628 return SLAP_CB_CONTINUE;
1632 ** Builds a filter for searching for the
1633 ** group entries, according to the objectClass.
1636 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1640 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1642 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1643 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1644 + agd->agd_oc->soc_cname.bv_len;
1645 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1647 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1649 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1653 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1655 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1666 static ConfigDriver ag_cfgen;
1668 static ConfigTable agcfg[] = {
1669 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1670 4, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1671 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1672 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1673 "EQUALITY caseIgnoreMatch "
1674 "SYNTAX OMsDirectoryString "
1675 "X-ORDERED 'VALUES' )",
1678 { "autogroup-memberof-ad", "memberOf attribute",
1679 2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen,
1680 "( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' "
1681 "DESC 'memberOf attribute' "
1682 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1685 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1688 static ConfigOCs agocs[] = {
1689 { "( OLcfgCtOc:2.1 "
1690 "NAME 'olcAutomaticGroups' "
1691 "DESC 'Automatic groups configuration' "
1692 "SUP olcOverlayConfig "
1695 "$ olcAGmemberOfAd "
1698 Cft_Overlay, agcfg, NULL, NULL },
1704 ag_cfgen( ConfigArgs *c )
1706 slap_overinst *on = (slap_overinst *)c->bi;
1707 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1708 autogroup_def_t *agd;
1709 autogroup_entry_t *age;
1713 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1716 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1717 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1718 agi->agi_def = NULL;
1719 agi->agi_entry = NULL;
1720 on->on_bi.bi_private = (void *)agi;
1724 age = agi->agi_entry;
1726 if ( c->op == SLAP_CONFIG_EMIT ) {
1730 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1732 char *ptr = c->cr_msg;
1734 assert(agd->agd_oc != NULL);
1735 assert(agd->agd_member_url_ad != NULL);
1736 assert(agd->agd_member_ad != NULL);
1738 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1739 SLAP_X_ORDERED_FMT "%s %s %s", i,
1740 agd->agd_oc->soc_cname.bv_val,
1741 agd->agd_member_url_ad->ad_cname.bv_val,
1742 agd->agd_member_ad->ad_cname.bv_val );
1744 bv.bv_val = c->cr_msg;
1745 bv.bv_len = ptr - bv.bv_val;
1746 value_add_one ( &c->rvalue_vals, &bv );
1751 case AG_MEMBER_OF_AD:
1752 if ( agi->agi_memberof_ad != NULL ){
1753 value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname );
1764 }else if ( c->op == LDAP_MOD_DELETE ) {
1766 autogroup_def_t *agd_next;
1767 autogroup_entry_t *age_next;
1768 autogroup_filter_t *agf = age->age_filter,
1771 for ( agd_next = agd; agd_next; agd = agd_next ) {
1772 agd_next = agd->agd_next;
1777 for ( age_next = age ; age_next ; age = age_next ) {
1778 age_next = age->age_next;
1780 ch_free( age->age_dn.bv_val );
1781 ch_free( age->age_ndn.bv_val );
1783 for( agf_next = agf ; agf_next ; agf = agf_next ){
1784 agf_next = agf->agf_next;
1786 filter_free( agf->agf_filter );
1787 ch_free( agf->agf_filterstr.bv_val );
1788 ch_free( agf->agf_dn.bv_val );
1789 ch_free( agf->agf_ndn.bv_val );
1790 anlist_free( agf->agf_anlist, 1, NULL );
1794 ldap_pvt_thread_mutex_init( &age->age_mutex );
1799 on->on_bi.bi_private = NULL;
1802 autogroup_def_t **agdp;
1803 autogroup_entry_t *age_next, *age_prev;
1804 autogroup_filter_t *agf,
1807 for ( i = 0, agdp = &agi->agi_def;
1810 if ( *agdp == NULL) {
1813 agdp = &(*agdp)->agd_next;
1817 *agdp = agd->agd_next;
1819 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1820 age_next = age->age_next;
1822 if( age->age_def == agd ) {
1823 agf = age->age_filter;
1825 ch_free( age->age_dn.bv_val );
1826 ch_free( age->age_ndn.bv_val );
1828 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1829 agf_next = agf->agf_next;
1830 filter_free( agf->agf_filter );
1831 ch_free( agf->agf_filterstr.bv_val );
1832 ch_free( agf->agf_dn.bv_val );
1833 ch_free( agf->agf_ndn.bv_val );
1834 anlist_free( agf->agf_anlist, 1, NULL );
1838 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1843 if( age_prev != NULL ) {
1844 age_prev->age_next = age_next;
1859 autogroup_def_t **agdp,
1861 ObjectClass *oc = NULL;
1862 AttributeDescription *member_url_ad = NULL,
1867 oc = oc_find( c->argv[ 1 ] );
1869 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1870 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1871 "unable to find ObjectClass \"%s\"",
1873 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1874 c->log, c->cr_msg, 0 );
1879 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1880 if( rc != LDAP_SUCCESS ) {
1881 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1882 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1883 "unable to find AttributeDescription \"%s\"",
1885 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1886 c->log, c->cr_msg, 0 );
1890 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1891 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1892 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1893 "AttributeDescription \"%s\" ",
1894 "must be of a subtype \"labeledURI\"",
1896 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1897 c->log, c->cr_msg, 0 );
1901 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1902 if( rc != LDAP_SUCCESS ) {
1903 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1904 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1905 "unable to find AttributeDescription \"%s\"",
1907 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1908 c->log, c->cr_msg, 0 );
1912 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1913 /* The same URL attribute / member attribute pair
1914 * cannot be repeated */
1916 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1917 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1918 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1919 "URL attributeDescription \"%s\" already mapped",
1920 member_ad->ad_cname.bv_val );
1921 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1922 c->log, c->cr_msg, 0 );
1923 /* return 1; //warning*/
1927 if ( c->valx > 0 ) {
1930 for ( i = 0, agdp = &agi->agi_def ;
1933 if ( *agdp == NULL ) {
1934 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1935 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1936 "invalid index {%d}",
1938 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1939 c->log, c->cr_msg, 0 );
1943 agdp = &(*agdp)->agd_next;
1948 for ( agdp = &agi->agi_def; *agdp;
1949 agdp = &(*agdp)->agd_next )
1953 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1955 (*agdp)->agd_oc = oc;
1956 (*agdp)->agd_member_url_ad = member_url_ad;
1957 (*agdp)->agd_member_ad = member_ad;
1958 (*agdp)->agd_next = agd_next;
1962 case AG_MEMBER_OF_AD: {
1963 AttributeDescription *memberof_ad = NULL;
1966 rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text );
1967 if( rc != LDAP_SUCCESS ) {
1968 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1969 "\"autogroup-memberof-ad <memberof-ad>\": "
1970 "unable to find AttributeDescription \"%s\"",
1972 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1973 c->log, c->cr_msg, 0 );
1977 if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */
1978 && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */
1980 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1981 "memberof attribute=\"%s\" must either "
1982 "have DN (%s) or nameUID (%s) syntax",
1983 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
1984 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1985 c->log, c->cr_msg, 0 );
1989 agi->agi_memberof_ad = memberof_ad;
2001 extern int slapMode;
2004 ** Do a search for all the groups in the
2005 ** database, and add them to out internal list.
2012 slap_overinst *on = (slap_overinst *) be->bd_info;
2013 autogroup_info_t *agi = on->on_bi.bi_private;
2014 autogroup_def_t *agd;
2017 slap_callback cb = { 0 };
2019 void *thrctx = ldap_pvt_thread_pool_context();
2020 Connection conn = { 0 };
2021 OperationBuffer opbuf;
2023 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
2025 if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
2029 connection_fake_init( &conn, &opbuf, thrctx );
2032 op->ors_attrsonly = 0;
2033 op->o_tag = LDAP_REQ_SEARCH;
2034 op->o_dn = be->be_rootdn;
2035 op->o_ndn = be->be_rootndn;
2037 op->o_req_dn = be->be_suffix[0];
2038 op->o_req_ndn = be->be_nsuffix[0];
2040 op->ors_scope = LDAP_SCOPE_SUBTREE;
2041 op->ors_deref = LDAP_DEREF_NEVER;
2042 op->ors_limit = NULL;
2043 op->ors_tlimit = SLAP_NO_LIMIT;
2044 op->ors_slimit = SLAP_NO_LIMIT;
2045 op->ors_attrs = slap_anlist_no_attrs;
2046 op->o_do_not_cache = 1;
2049 op->o_bd->bd_info = (BackendInfo *)on->on_info;
2052 cb.sc_private = &ags;
2053 cb.sc_response = autogroup_group_add_cb;
2054 cb.sc_cleanup = NULL;
2057 op->o_callback = &cb;
2059 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
2060 SlapReply rs = { REP_RESULT };
2062 autogroup_build_def_filter(agd, op);
2066 op->o_bd->be_search( op, &rs );
2068 filter_free_x( op, op->ors_filter, 1 );
2069 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
2072 if( ! agi->agi_memberof_ad ){
2074 const char *text = NULL;
2076 rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text );
2077 if ( rc != LDAP_SUCCESS ) {
2078 Debug( LDAP_DEBUG_ANY, "autogroup_db_open: "
2079 "unable to find attribute=\"%s\": %s (%d)\n",
2080 SLAPD_MEMBEROF_ATTR, text, rc );
2093 slap_overinst *on = (slap_overinst *) be->bd_info;
2095 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
2097 if ( on->on_bi.bi_private ) {
2098 autogroup_info_t *agi = on->on_bi.bi_private;
2099 autogroup_entry_t *age = agi->agi_entry,
2101 autogroup_filter_t *agf, *agf_next;
2103 for ( age_next = age; age_next; age = age_next ) {
2104 age_next = age->age_next;
2106 ch_free( age->age_dn.bv_val );
2107 ch_free( age->age_ndn.bv_val );
2109 agf = age->age_filter;
2111 for ( agf_next = agf; agf_next; agf = agf_next ) {
2112 agf_next = agf->agf_next;
2114 filter_free( agf->agf_filter );
2115 ch_free( agf->agf_filterstr.bv_val );
2116 ch_free( agf->agf_dn.bv_val );
2117 ch_free( agf->agf_ndn.bv_val );
2118 anlist_free( agf->agf_anlist, 1, NULL );
2122 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
2131 autogroup_db_destroy(
2135 slap_overinst *on = (slap_overinst *) be->bd_info;
2137 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
2139 if ( on->on_bi.bi_private ) {
2140 autogroup_info_t *agi = on->on_bi.bi_private;
2141 autogroup_def_t *agd = agi->agi_def,
2144 for ( agd_next = agd; agd_next; agd = agd_next ) {
2145 agd_next = agd->agd_next;
2150 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
2157 static slap_overinst autogroup = { { NULL } };
2161 autogroup_initialize(void)
2164 autogroup.on_bi.bi_type = "autogroup";
2166 autogroup.on_bi.bi_db_open = autogroup_db_open;
2167 autogroup.on_bi.bi_db_close = autogroup_db_close;
2168 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
2170 autogroup.on_bi.bi_op_add = autogroup_add_entry;
2171 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
2172 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
2173 autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
2175 autogroup.on_response = autogroup_response;
2177 autogroup.on_bi.bi_cf_ocs = agocs;
2179 rc = config_register_schema( agcfg, agocs );
2184 return overlay_register( &autogroup );
2188 init_module( int argc, char *argv[] )
2190 return autogroup_initialize();