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 static slap_overinst autogroup;
43 /* Filter represents the memberURL of a group. */
44 typedef struct autogroup_filter_t {
45 struct berval agf_dn; /* The base DN in memberURL */
46 struct berval agf_ndn;
47 struct berval agf_filterstr;
50 AttributeName *agf_anlist;
51 struct autogroup_filter_t *agf_next;
54 /* Description of group attributes. */
55 typedef struct autogroup_def_t {
57 AttributeDescription *agd_member_url_ad;
58 AttributeDescription *agd_member_ad;
59 struct autogroup_def_t *agd_next;
62 /* Represents the group entry. */
63 typedef struct autogroup_entry_t {
66 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
67 autogroup_def_t *age_def; /* Attribute definition */
68 ldap_pvt_thread_mutex_t age_mutex;
69 int age_mustrefresh; /* Defined in request to refresh in response */
70 int age_modrdn_olddnmodified; /* Defined in request to refresh in response */
71 struct autogroup_entry_t *age_next;
74 /* Holds pointers to attribute definitions and groups. */
75 typedef struct autogroup_info_t {
76 autogroup_def_t *agi_def; /* Group attributes definitions. */
77 autogroup_entry_t *agi_entry; /* Group entries. */
78 AttributeDescription *agi_memberof_ad; /* memberOf attribute description */
79 ldap_pvt_thread_mutex_t agi_mutex;
82 /* Search callback for adding groups initially. */
83 typedef struct autogroup_sc_t {
84 autogroup_info_t *ags_info; /* Group definitions and entries. */
85 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
88 /* Used for adding members, found when searching, to a group. */
89 typedef struct autogroup_ga_t {
90 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
91 autogroup_filter_t *agg_filter; /* Current filter */
92 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
93 this entry with the search results. */
95 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
96 search results which will be added to the group. */
98 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
99 have to search for the last mod added. */
104 ** dn, ndn - the DN of the member to add
105 ** age - the group to which the member DN will be added
108 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
110 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
111 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
112 SlapReply sreply = {REP_RESULT};
113 BerValue *vals, *nvals;
114 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
116 unsigned long opid = op->o_opid;
119 assert( dn != NULL );
120 assert( ndn != NULL );
121 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
122 dn->bv_val, age->age_dn.bv_val, 0);
124 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
125 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
126 ber_dupbv( vals, dn );
127 BER_BVZERO( &vals[ 1 ] );
128 ber_dupbv( nvals, ndn );
129 BER_BVZERO( &nvals[ 1 ] );
131 modlist->sml_op = LDAP_MOD_ADD;
132 modlist->sml_desc = age->age_def->agd_member_ad;
133 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
134 modlist->sml_values = vals;
135 modlist->sml_nvalues = nvals;
136 modlist->sml_numvals = 1;
137 modlist->sml_flags = SLAP_MOD_INTERNAL;
138 modlist->sml_next = NULL;
140 o.o_opid = 0; /* shared with op, saved above */
141 o.o_tag = LDAP_REQ_MODIFY;
143 o.orm_modlist = modlist;
144 o.o_dn = op->o_bd->be_rootdn;
145 o.o_ndn = op->o_bd->be_rootndn;
146 o.o_req_dn = age->age_dn;
147 o.o_req_ndn = age->age_ndn;
148 o.o_permissive_modify = 1;
149 o.o_dont_replicate = 1;
150 o.orm_no_opattrs = 1;
151 o.o_managedsait = SLAP_CONTROL_CRITICAL;
152 o.o_relax = SLAP_CONTROL_CRITICAL;
154 oex.oe_key = (void *)&autogroup;
155 LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
157 o.o_bd->bd_info = (BackendInfo *)on->on_info;
158 (void)op->o_bd->be_modify( &o, &sreply );
159 o.o_bd->bd_info = (BackendInfo *)on;
161 LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
163 slap_mods_free( modlist, 1 );
166 return sreply.sr_err;
170 ** e - the entry where to get the attribute values
171 ** age - the group to which the values will be added
174 autogroup_add_member_values_to_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
176 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
177 Modifications modlist;
178 SlapReply sreply = {REP_RESULT};
179 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
181 unsigned long opid = op->o_opid;
184 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
185 dn->bv_val, age->age_dn.bv_val, 0);
187 modlist.sml_op = LDAP_MOD_ADD;
188 modlist.sml_desc = age->age_def->agd_member_ad;
189 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
190 modlist.sml_values = attr->a_vals;
191 modlist.sml_nvalues = attr->a_nvals;
192 modlist.sml_numvals = attr->a_numvals;
193 modlist.sml_flags = SLAP_MOD_INTERNAL;
194 modlist.sml_next = NULL;
197 o.o_tag = LDAP_REQ_MODIFY;
199 o.orm_modlist = &modlist;
200 o.o_dn = op->o_bd->be_rootdn;
201 o.o_ndn = op->o_bd->be_rootndn;
202 o.o_req_dn = age->age_dn;
203 o.o_req_ndn = age->age_ndn;
204 o.o_permissive_modify = 1;
205 o.o_dont_replicate = 1;
206 o.orm_no_opattrs = 1;
207 o.o_managedsait = SLAP_CONTROL_CRITICAL;
208 o.o_relax = SLAP_CONTROL_CRITICAL;
210 oex.oe_key = (void *)&autogroup;
211 LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
213 o.o_bd->bd_info = (BackendInfo *)on->on_info;
214 (void)op->o_bd->be_modify( &o, &sreply );
215 o.o_bd->bd_info = (BackendInfo *)on;
217 LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
219 return sreply.sr_err;
223 ** dn,ndn - the DN to be deleted
224 ** age - the group from which the DN will be deleted
225 ** If we pass a NULL dn and ndn, all members are deleted from the group.
228 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
230 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
231 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
232 SlapReply sreply = {REP_RESULT};
233 BerValue *vals, *nvals;
234 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
236 unsigned long opid = op->o_opid;
239 if ( dn == NULL || ndn == NULL ) {
240 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
241 age->age_dn.bv_val, 0 ,0);
243 modlist->sml_values = NULL;
244 modlist->sml_nvalues = NULL;
245 modlist->sml_numvals = 0;
247 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
248 dn->bv_val, age->age_dn.bv_val, 0);
250 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
251 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
252 ber_dupbv( vals, dn );
253 BER_BVZERO( &vals[ 1 ] );
254 ber_dupbv( nvals, ndn );
255 BER_BVZERO( &nvals[ 1 ] );
257 modlist->sml_values = vals;
258 modlist->sml_nvalues = nvals;
259 modlist->sml_numvals = 1;
263 modlist->sml_op = LDAP_MOD_DELETE;
264 modlist->sml_desc = age->age_def->agd_member_ad;
265 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
266 modlist->sml_flags = SLAP_MOD_INTERNAL;
267 modlist->sml_next = NULL;
271 o.o_tag = LDAP_REQ_MODIFY;
272 o.orm_modlist = modlist;
273 o.o_dn = op->o_bd->be_rootdn;
274 o.o_ndn = op->o_bd->be_rootndn;
275 o.o_req_dn = age->age_dn;
276 o.o_req_ndn = age->age_ndn;
277 o.o_relax = SLAP_CONTROL_CRITICAL;
278 o.o_managedsait = SLAP_CONTROL_CRITICAL;
279 o.o_permissive_modify = 1;
280 o.o_dont_replicate = 1;
281 o.orm_no_opattrs = 1;
283 oex.oe_key = (void *)&autogroup;
284 LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
286 o.o_bd->bd_info = (BackendInfo *)on->on_info;
287 (void)op->o_bd->be_modify( &o, &sreply );
288 o.o_bd->bd_info = (BackendInfo *)on;
290 LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
292 slap_mods_free( modlist, 1 );
295 return sreply.sr_err;
299 ** e - the entry where to get the attribute values
300 ** age - the group from which the values will be deleted
303 autogroup_delete_member_values_from_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
305 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
306 Modifications modlist;
307 SlapReply sreply = {REP_RESULT};
308 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
310 unsigned long opid = op->o_opid;
313 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n",
314 dn->bv_val, age->age_dn.bv_val, 0);
316 modlist.sml_op = LDAP_MOD_DELETE;
317 modlist.sml_desc = age->age_def->agd_member_ad;
318 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
319 modlist.sml_values = attr->a_vals;
320 modlist.sml_nvalues = attr->a_nvals;
321 modlist.sml_numvals = attr->a_numvals;
322 modlist.sml_flags = SLAP_MOD_INTERNAL;
323 modlist.sml_next = NULL;
326 o.o_tag = LDAP_REQ_MODIFY;
328 o.orm_modlist = &modlist;
329 o.o_dn = op->o_bd->be_rootdn;
330 o.o_ndn = op->o_bd->be_rootndn;
331 o.o_req_dn = age->age_dn;
332 o.o_req_ndn = age->age_ndn;
333 o.o_permissive_modify = 1;
334 o.o_dont_replicate = 1;
335 o.orm_no_opattrs = 1;
336 o.o_managedsait = SLAP_CONTROL_CRITICAL;
337 o.o_relax = SLAP_CONTROL_CRITICAL;
339 oex.oe_key = (void *)&autogroup;
340 LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
342 o.o_bd->bd_info = (BackendInfo *)on->on_info;
343 (void)op->o_bd->be_modify( &o, &sreply );
344 o.o_bd->bd_info = (BackendInfo *)on;
347 LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
349 return sreply.sr_err;
353 ** Callback used to add entries to a group,
354 ** which are going to be written in the database
355 ** (used in bi_op_add)
356 ** The group is passed in autogroup_ga_t->agg_group
359 autogroup_member_search_cb( Operation *op, SlapReply *rs )
361 assert( op->o_tag == LDAP_REQ_SEARCH );
363 if ( rs->sr_type == REP_SEARCH ) {
364 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
365 autogroup_entry_t *age = agg->agg_group;
366 autogroup_filter_t *agf = agg->agg_filter;
368 const char *text = NULL;
370 struct berval *vals, *nvals;
371 struct berval lvals[ 2 ], lnvals[ 2 ];
374 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
375 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
377 if ( agf->agf_anlist ) {
378 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
381 nvals = attr->a_nvals;
382 numvals = attr->a_numvals;
388 lvals[ 0 ] = rs->sr_entry->e_name;
389 BER_BVZERO( &lvals[ 1 ] );
390 lnvals[ 0 ] = rs->sr_entry->e_nname;
391 BER_BVZERO( &lnvals[ 1 ] );
397 mod.sm_op = LDAP_MOD_ADD;
398 mod.sm_desc = age->age_def->agd_member_ad;
399 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
400 mod.sm_values = vals;
401 mod.sm_nvalues = nvals;
402 mod.sm_numvals = numvals;
404 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
411 ** Callback used to add entries to a group, which is already in the database.
412 ** (used in on_response)
413 ** The group is passed in autogroup_ga_t->agg_group
417 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
419 assert( op->o_tag == LDAP_REQ_SEARCH );
421 if ( rs->sr_type == REP_SEARCH ) {
422 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
423 autogroup_entry_t *age = agg->agg_group;
424 autogroup_filter_t *agf = agg->agg_filter;
425 Modifications *modlist;
426 struct berval *vals, *nvals;
427 struct berval lvals[ 2 ], lnvals[ 2 ];
430 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
431 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
433 if ( agf->agf_anlist ) {
434 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
437 nvals = attr->a_nvals;
438 numvals = attr->a_numvals;
444 lvals[ 0 ] = rs->sr_entry->e_name;
445 BER_BVZERO( &lvals[ 1 ] );
446 lnvals[ 0 ] = rs->sr_entry->e_nname;
447 BER_BVZERO( &lnvals[ 1 ] );
454 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
456 modlist->sml_op = LDAP_MOD_ADD;
457 modlist->sml_desc = age->age_def->agd_member_ad;
458 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
460 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
461 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
462 modlist->sml_numvals = numvals;
464 modlist->sml_flags = SLAP_MOD_INTERNAL;
465 modlist->sml_next = NULL;
467 if ( agg->agg_mod == NULL ) {
468 agg->agg_mod = modlist;
469 agg->agg_mod_last = modlist;
471 agg->agg_mod_last->sml_next = modlist;
472 agg->agg_mod_last = modlist;
483 ** Adds all entries matching the passed filter to the specified group.
484 ** If modify == 1, then we modify the group's entry in the database using be_modify.
485 ** If modify == 0, then, we must supply a rw entry for the group,
486 ** because we only modify the entry, without calling be_modify.
487 ** e - the group entry, to which the members will be added
492 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
494 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
496 SlapReply rs = { REP_SEARCH };
497 slap_callback cb = { 0 };
498 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
502 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
503 age->age_dn.bv_val, 0, 0);
506 o.o_tag = LDAP_REQ_SEARCH;
508 o.o_dn = op->o_bd->be_rootdn;
509 o.o_ndn = op->o_bd->be_rootndn;
510 o.o_req_dn = agf->agf_dn;
511 o.o_req_ndn = agf->agf_ndn;
513 o.ors_filterstr = agf->agf_filterstr;
514 o.ors_filter = agf->agf_filter;
516 o.ors_scope = agf->agf_scope;
517 o.ors_deref = LDAP_DEREF_NEVER;
519 o.ors_tlimit = SLAP_NO_LIMIT;
520 o.ors_slimit = SLAP_NO_LIMIT;
521 o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
522 o.o_do_not_cache = 1;
525 agg.agg_filter = agf;
527 agg.agg_mod_last = NULL;
529 cb.sc_private = &agg;
532 cb.sc_response = autogroup_member_search_modify_cb;
534 cb.sc_response = autogroup_member_search_cb;
537 cb.sc_cleanup = NULL;
542 o.o_bd->bd_info = (BackendInfo *)on->on_info;
543 op->o_bd->be_search( &o, &rs );
544 o.o_bd->bd_info = (BackendInfo *)on;
546 if ( modify == 1 && agg.agg_mod ) {
547 unsigned long opid = op->o_opid;
549 rs_reinit( &rs, REP_RESULT );
553 o.o_callback = &null_cb;
554 o.o_tag = LDAP_REQ_MODIFY;
555 o.orm_modlist = agg.agg_mod;
556 o.o_dn = op->o_bd->be_rootdn;
557 o.o_ndn = op->o_bd->be_rootndn;
558 o.o_req_dn = age->age_dn;
559 o.o_req_ndn = age->age_ndn;
560 o.o_relax = SLAP_CONTROL_CRITICAL;
561 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
562 o.o_permissive_modify = 1;
563 o.o_dont_replicate = 1;
564 o.orm_no_opattrs = 1;
566 oex.oe_key = (void *)&autogroup;
567 LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
569 o.o_bd->bd_info = (BackendInfo *)on->on_info;
570 (void)op->o_bd->be_modify( &o, &rs );
571 o.o_bd->bd_info = (BackendInfo *)on;
573 LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
575 slap_mods_free(agg.agg_mod, 1);
583 ** Adds a group to the internal list from the passed entry.
584 ** scan specifies whether to add all maching members to the group.
585 ** modify specifies whether to modify the given group entry (when modify == 0),
586 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
587 ** agi - pointer to the groups and the attribute definitions
588 ** agd - the attribute definition of the added group
589 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
590 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
593 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
595 autogroup_entry_t **agep = &agi->agi_entry;
596 autogroup_filter_t *agf, *agf_prev = NULL;
597 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
598 LDAPURLDesc *lud = NULL;
601 int rc = 0, match = 1, null_entry = 0;
604 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
605 LDAP_SUCCESS || e == NULL ) {
606 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
613 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
614 e->e_name.bv_val, 0, 0);
616 if ( agi->agi_entry != NULL ) {
617 for ( ; *agep ; agep = &(*agep)->age_next ) {
618 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
620 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
628 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
629 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
630 (*agep)->age_def = agd;
631 (*agep)->age_filter = NULL;
632 (*agep)->age_mustrefresh = 0;
633 (*agep)->age_modrdn_olddnmodified = 0;
635 ber_dupbv( &(*agep)->age_dn, &e->e_name );
636 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
638 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
640 if ( null_entry == 1 ) {
642 overlay_entry_release_ov( op, e, 0, on );
646 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
648 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
650 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
652 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
653 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
659 agf->agf_scope = lud->lud_scope;
661 if ( lud->lud_dn == NULL ) {
662 BER_BVSTR( &dn, "" );
664 ber_str2bv( lud->lud_dn, 0, 0, &dn );
667 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
668 if ( rc != LDAP_SUCCESS ) {
669 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
674 if ( lud->lud_filter != NULL ) {
675 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
676 agf->agf_filter = str2filter( lud->lud_filter );
678 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: URL filter is missing <%s>\n", bv->bv_val,0,0);
683 if ( lud->lud_attrs != NULL ) {
686 for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
691 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n",
694 filter_free( agf->agf_filter );
695 ch_free( agf->agf_filterstr.bv_val );
696 ch_free( agf->agf_dn.bv_val );
697 ch_free( agf->agf_ndn.bv_val );
698 ldap_free_urldesc( lud );
703 agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
705 if ( agf->agf_anlist == NULL ) {
706 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
707 lud->lud_attrs[0], 0, 0 );
709 filter_free( agf->agf_filter );
710 ch_free( agf->agf_filterstr.bv_val );
711 ch_free( agf->agf_dn.bv_val );
712 ch_free( agf->agf_ndn.bv_val );
713 ldap_free_urldesc( lud );
719 agf->agf_next = NULL;
721 if( (*agep)->age_filter == NULL ) {
722 (*agep)->age_filter = agf;
725 if( agf_prev != NULL ) {
726 agf_prev->agf_next = agf;
732 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
735 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
736 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
738 ldap_free_urldesc( lud );
745 ch_free( agf->agf_ndn.bv_val );
746 ch_free( agf->agf_dn.bv_val );
747 ldap_free_urldesc( lud );
752 if ( null_entry == 1 ) {
759 ** Used when opening the database to add all existing
760 ** groups from the database to our internal list.
763 autogroup_group_add_cb( Operation *op, SlapReply *rs )
765 assert( op->o_tag == LDAP_REQ_SEARCH );
767 if ( rs->sr_type == REP_SEARCH ) {
768 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
770 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
771 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
773 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
779 typedef struct ag_addinfo {
782 autogroup_def_t *agd;
786 autogroup_add_entry_cb( Operation *op, SlapReply *rs )
788 slap_callback *sc = op->o_callback;
789 ag_addinfo *aa = sc->sc_private;
790 slap_overinst *on = aa->on;
791 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
792 BackendInfo *bi = op->o_bd->bd_info;
794 if ( rs->sr_err != LDAP_SUCCESS )
797 op->o_bd->bd_info = (BackendInfo *)on;
798 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
800 autogroup_add_group( op, agi, aa->agd, aa->e, NULL, 1 , 0);
802 autogroup_entry_t *age;
803 autogroup_filter_t *agf;
804 struct berval odn, ondn;
807 /* must use rootdn when calling test_filter */
810 op->o_dn = op->o_bd->be_rootdn;
811 op->o_ndn = op->o_bd->be_rootndn;
813 for ( age = agi->agi_entry; age ; age = age->age_next ) {
814 ldap_pvt_thread_mutex_lock( &age->age_mutex );
816 /* Check if any of the filters are the suffix to the entry DN.
817 If yes, we can test that filter against the entry. */
819 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
820 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
821 rc = test_filter( op, aa->e, agf->agf_filter );
822 if ( rc == LDAP_COMPARE_TRUE ) {
823 if ( agf->agf_anlist ) {
824 Attribute *a = attr_find( aa->e->e_attrs, agf->agf_anlist[0].an_desc );
826 autogroup_add_member_values_to_group( op, &op->o_req_dn, age, a );
828 autogroup_add_member_to_group( op, &aa->e->e_name, &aa->e->e_nname, age );
834 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
839 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
841 op->o_bd->bd_info = bi;
844 op->o_callback = sc->sc_next;
845 op->o_tmpfree( sc, op->o_tmpmemctx );
847 return SLAP_CB_CONTINUE;
851 ** When adding a group, we first strip any existing members,
852 ** and add all which match the filters ourselfs.
855 autogroup_add_entry( Operation *op, SlapReply *rs)
857 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
858 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
859 autogroup_def_t *agd = agi->agi_def;
860 slap_callback *sc = NULL;
861 ag_addinfo *aa = NULL;
863 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
864 op->ora_e->e_name.bv_val, 0, 0);
866 sc = op->o_tmpcalloc( sizeof(slap_callback) + sizeof(ag_addinfo), 1, op->o_tmpmemctx );
867 sc->sc_private = (sc+1);
868 sc->sc_response = autogroup_add_entry_cb;
872 sc->sc_next = op->o_callback;
875 /* Check if it's a group. */
876 for ( ; agd ; agd = agd->agd_next ) {
877 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
879 const char *text = NULL;
882 mod.sm_op = LDAP_MOD_DELETE;
883 mod.sm_desc = agd->agd_member_ad;
884 mod.sm_type = agd->agd_member_ad->ad_cname;
885 mod.sm_values = NULL;
886 mod.sm_nvalues = NULL;
888 /* We don't want any member attributes added by the user. */
889 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
897 return SLAP_CB_CONTINUE;
901 ** agi - internal group and attribute definitions list
902 ** e - the group to remove from the internal list
905 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
907 autogroup_entry_t *age = agi->agi_entry,
912 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
913 age->age_dn.bv_val, 0, 0);
915 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
916 age_next = age->age_next;
919 autogroup_filter_t *agf = age->age_filter,
922 if ( age_prev != NULL ) {
923 age_prev->age_next = age_next;
925 agi->agi_entry = NULL;
928 ch_free( age->age_dn.bv_val );
929 ch_free( age->age_ndn.bv_val );
931 for( agf_next = agf ; agf_next ; agf = agf_next ){
932 agf_next = agf->agf_next;
934 filter_free( agf->agf_filter );
935 ch_free( agf->agf_filterstr.bv_val );
936 ch_free( agf->agf_dn.bv_val );
937 ch_free( agf->agf_ndn.bv_val );
938 anlist_free( agf->agf_anlist, 1, NULL );
942 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
943 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
952 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
959 autogroup_delete_entry( Operation *op, SlapReply *rs)
961 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
962 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
963 autogroup_entry_t *age, *age_prev, *age_next;
964 autogroup_filter_t *agf;
966 int matched_group = 0, rc = 0;
967 struct berval odn, ondn;
970 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
971 if ( oex->oe_key == (void *)&autogroup )
972 return SLAP_CB_CONTINUE;
975 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
977 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
979 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
980 LDAP_SUCCESS || e == NULL ) {
981 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
982 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
983 return SLAP_CB_CONTINUE;
986 /* Check if the entry to be deleted is one of our groups. */
987 for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) {
989 ldap_pvt_thread_mutex_lock( &age->age_mutex );
990 age_next = age->age_next;
992 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
997 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
1000 autogroup_delete_group( agi, age );
1005 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1008 if ( matched_group == 1 ) {
1009 overlay_entry_release_ov( op, e, 0, on );
1010 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1011 return SLAP_CB_CONTINUE;
1014 /* Check if the entry matches any of the groups.
1015 If yes, we can delete the entry from that group. */
1019 op->o_dn = op->o_bd->be_rootdn;
1020 op->o_ndn = op->o_bd->be_rootndn;
1022 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1023 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1025 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
1026 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1027 rc = test_filter( op, e, agf->agf_filter );
1028 if ( rc == LDAP_COMPARE_TRUE ) {
1029 /* If the attribute is retrieved from the entry, we don't know what to delete
1030 ** So the group must be entirely refreshed
1031 ** But the refresh can't be done now because the entry is not deleted
1032 ** So the group is marked as mustrefresh
1034 if ( agf->agf_anlist ) {
1035 age->age_mustrefresh = 1;
1037 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
1043 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1048 overlay_entry_release_ov( op, e, 0, on );
1049 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1051 return SLAP_CB_CONTINUE;
1055 autogroup_response( Operation *op, SlapReply *rs )
1057 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1058 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1059 autogroup_def_t *agd = agi->agi_def;
1060 autogroup_entry_t *age;
1061 autogroup_filter_t *agf;
1062 BerValue new_dn, new_ndn, pdn;
1064 Attribute *a, *ea, *attrs;
1065 int is_olddn, is_newdn, is_value_refresh, dn_equal;
1068 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
1069 if ( oex->oe_key == (void *)&autogroup )
1073 /* Handle all cases where a refresh of the group is needed */
1074 if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
1075 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
1077 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1079 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1080 /* Request detected that the group must be refreshed */
1082 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1084 if ( age->age_mustrefresh ) {
1085 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1087 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1088 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1092 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1095 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1097 } else if ( op->o_tag == LDAP_REQ_MODRDN ) {
1098 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
1100 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
1102 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1104 if ( op->oq_modrdn.rs_newSup ) {
1105 pdn = *op->oq_modrdn.rs_newSup;
1107 dnParent( &op->o_req_dn, &pdn );
1109 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
1111 if ( op->oq_modrdn.rs_nnewSup ) {
1112 pdn = *op->oq_modrdn.rs_nnewSup;
1114 dnParent( &op->o_req_ndn, &pdn );
1116 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
1118 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
1120 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
1122 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
1123 LDAP_SUCCESS || e == NULL ) {
1124 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
1125 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1126 return SLAP_CB_CONTINUE;
1129 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1133 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
1134 overlay_entry_release_ov( op, e, 0, on );
1135 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1136 return SLAP_CB_CONTINUE;
1140 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
1141 for ( ; agd; agd = agd->agd_next ) {
1143 if ( value_find_ex( slap_schema.si_ad_objectClass,
1144 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1145 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1146 a->a_nvals, &agd->agd_oc->soc_cname,
1147 op->o_tmpmemctx ) == 0 )
1149 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1152 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
1154 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
1155 ber_dupbv( &age->age_dn, &new_dn );
1156 ber_dupbv( &age->age_ndn, &new_ndn );
1158 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1159 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1160 overlay_entry_release_ov( op, e, 0, on );
1161 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1162 return SLAP_CB_CONTINUE;
1170 1. check if the orginal entry's DN is in the group.
1171 2. chceck if the any of the group filter's base DN is a suffix of the new DN
1173 If 1 and 2 are both false, we do nothing.
1174 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
1175 If 1 is false, and 2 is true, we check the entry against the group's filters,
1176 and add it's DN to the group.
1177 If 1 is true, and 2 is false, we delete the entry's DN from the group.
1179 attrs = attrs_dup( e->e_attrs );
1180 overlay_entry_release_ov( op, e, 0, on );
1181 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1184 is_value_refresh = 0;
1186 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1188 if ( age->age_filter && age->age_filter->agf_anlist ) {
1189 ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
1195 if ( age->age_modrdn_olddnmodified ) {
1196 /* Resquest already marked this group to be updated */
1198 is_value_refresh = 1;
1199 age->age_modrdn_olddnmodified = 0;
1202 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1203 LDAP_SUCCESS || group == NULL ) {
1204 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
1206 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1207 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1209 attrs_free( attrs );
1210 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1211 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1212 return SLAP_CB_CONTINUE;
1215 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1218 if ( value_find_ex( age->age_def->agd_member_ad,
1219 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1220 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1221 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1228 overlay_entry_release_ov( op, group, 0, on );
1232 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1233 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
1234 /* TODO: should retest filter as it could imply conditions on the dn */
1241 if ( is_value_refresh ) {
1242 if ( is_olddn != is_newdn ) {
1244 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1246 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1247 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1250 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1253 if ( is_olddn == 1 && is_newdn == 0 ) {
1255 autogroup_delete_member_values_from_group( op, &new_dn, age, ea );
1257 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1259 if ( is_olddn == 0 && is_newdn == 1 ) {
1261 struct berval odn, ondn;
1262 etmp.e_name = op->o_req_dn;
1263 etmp.e_nname = op->o_req_ndn;
1264 etmp.e_attrs = attrs;
1267 op->o_dn = op->o_bd->be_rootdn;
1268 op->o_ndn = op->o_bd->be_rootndn;
1270 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
1271 if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1273 autogroup_add_member_values_to_group( op, &new_dn, age, ea );
1275 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1282 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
1285 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1287 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1288 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1292 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1293 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1297 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1300 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1301 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1303 attrs_free( attrs );
1305 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1309 if ( op->o_tag == LDAP_REQ_MODIFY ) {
1310 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
1312 struct berval odn, ondn;
1313 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
1315 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1317 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1318 LDAP_SUCCESS || e == NULL ) {
1319 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1320 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1321 return SLAP_CB_CONTINUE;
1324 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1328 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1329 overlay_entry_release_ov( op, e, 0, on );
1330 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1331 return SLAP_CB_CONTINUE;
1334 /* If we modify a group's memberURL, we have to delete all of it's members,
1335 and add them anew, because we cannot tell from which memberURL a member was added. */
1336 for ( ; agd; agd = agd->agd_next ) {
1338 if ( value_find_ex( slap_schema.si_ad_objectClass,
1339 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1340 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1341 a->a_nvals, &agd->agd_oc->soc_cname,
1342 op->o_tmpmemctx ) == 0 )
1347 m = op->orm_modlist;
1349 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1350 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1352 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1355 for ( ; m ; m = m->sml_next ) {
1356 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
1357 autogroup_def_t *group_agd = age->age_def;
1358 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
1359 op->o_req_dn.bv_val, 0, 0);
1361 overlay_entry_release_ov( op, e, 0, on );
1363 autogroup_delete_member_from_group( op, NULL, NULL, age );
1364 autogroup_delete_group( agi, age );
1366 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
1368 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1369 return SLAP_CB_CONTINUE;
1373 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1377 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1380 overlay_entry_release_ov( op, e, 0, on );
1381 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1382 return SLAP_CB_CONTINUE;
1386 /* When modifying any of the attributes of an entry, we must
1387 check if the entry is in any of our groups, and if
1388 the modified entry maches any of the filters of that group.
1390 If the entry exists in a group, but the modified attributes do
1391 not match any of the group's filters, we delete the entry from that group.
1392 If the entry doesn't exist in a group, but matches a filter,
1393 we add it to that group.
1395 attrs = attrs_dup( e->e_attrs );
1396 overlay_entry_release_ov( op, e, 0, on );
1397 etmp.e_name = op->o_req_dn;
1398 etmp.e_nname = op->o_req_ndn;
1399 etmp.e_attrs = attrs;
1402 op->o_dn = op->o_bd->be_rootdn;
1403 op->o_ndn = op->o_bd->be_rootndn;
1405 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1409 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1411 if ( age->age_filter && age->age_filter->agf_anlist ) {
1412 ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
1418 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1419 LDAP_SUCCESS || group == NULL ) {
1420 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
1421 age->age_dn.bv_val, 0, 0);
1423 attrs_free( attrs );
1424 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1425 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1428 return SLAP_CB_CONTINUE;
1431 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1434 if ( value_find_ex( age->age_def->agd_member_ad,
1435 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1436 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1437 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1444 overlay_entry_release_ov( op, group, 0, on );
1446 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1447 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1448 if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1455 if ( is_olddn == 1 && is_newdn == 0 ) {
1457 autogroup_delete_member_values_from_group( op, &op->o_req_dn, age, ea );
1459 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1461 if ( is_olddn == 0 && is_newdn == 1 ) {
1463 autogroup_add_member_values_to_group( op, &op->o_req_dn, age, ea );
1465 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1468 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1473 attrs_free( attrs );
1475 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1479 return SLAP_CB_CONTINUE;
1483 ** Detect if filter contains a memberOf check for dn
1486 autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad )
1489 if ( f == NULL ) return 0;
1491 switch ( f->f_choice & SLAPD_FILTER_MASK ) {
1492 case LDAP_FILTER_AND:
1493 case LDAP_FILTER_OR:
1494 case LDAP_FILTER_NOT:
1495 for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) {
1496 result = result || autogroup_memberOf_filter( f, dn, memberof_ad );
1499 case LDAP_FILTER_EQUALITY:
1500 result = ( f->f_ava->aa_desc == memberof_ad &&
1501 ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 );
1511 ** When modifing a group, we must deny any modifications to the member attribute,
1512 ** because the group would be inconsistent.
1515 autogroup_modify_entry( Operation *op, SlapReply *rs)
1517 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1518 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1519 autogroup_def_t *agd = agi->agi_def;
1520 autogroup_entry_t *age;
1523 struct berval odn, ondn;
1526 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
1527 if ( oex->oe_key == (void *)&autogroup )
1528 return SLAP_CB_CONTINUE;
1531 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1532 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1534 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1535 LDAP_SUCCESS || e == NULL ) {
1536 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1537 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1538 return SLAP_CB_CONTINUE;
1543 op->o_dn = op->o_bd->be_rootdn;
1544 op->o_ndn = op->o_bd->be_rootndn;
1546 /* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */
1547 for ( age = agi->agi_entry; age ; age = age->age_next ) {
1548 autogroup_filter_t *agf;
1549 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1550 if ( agf->agf_anlist ) {
1552 for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
1553 if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
1554 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1555 int rc = test_filter( op, e, agf->agf_filter );
1556 if ( rc == LDAP_COMPARE_TRUE ) {
1557 age->age_mustrefresh = 1;
1564 if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) {
1565 age->age_mustrefresh = 1;
1572 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1575 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1576 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1577 return SLAP_CB_CONTINUE;
1581 for ( ; agd; agd = agd->agd_next ) {
1583 if ( value_find_ex( slap_schema.si_ad_objectClass,
1584 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1585 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1586 a->a_nvals, &agd->agd_oc->soc_cname,
1587 op->o_tmpmemctx ) == 0 )
1592 m = op->orm_modlist;
1594 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1595 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1598 for ( ; m ; m = m->sml_next ) {
1599 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1600 overlay_entry_release_ov( op, e, 0, on );
1601 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1602 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1603 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1604 return LDAP_CONSTRAINT_VIOLATION;
1611 /* an entry may only have one dynamic group class */
1616 overlay_entry_release_ov( op, e, 0, on );
1617 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1618 return SLAP_CB_CONTINUE;
1622 ** Detect if the olddn is part of a group and so if the group should be refreshed
1625 autogroup_modrdn_entry( Operation *op, SlapReply *rs)
1627 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1628 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1629 autogroup_entry_t *age;
1631 struct berval odn, ondn;
1634 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
1635 if ( oex->oe_key == (void *)&autogroup )
1636 return SLAP_CB_CONTINUE;
1639 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1640 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1642 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1643 LDAP_SUCCESS || e == NULL ) {
1644 Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1645 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1646 return SLAP_CB_CONTINUE;
1651 op->o_dn = op->o_bd->be_rootdn;
1652 op->o_ndn = op->o_bd->be_rootndn;
1654 /* Must check if a dn is modified */
1655 for ( age = agi->agi_entry; age ; age = age->age_next ) {
1656 autogroup_filter_t *agf;
1657 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1658 if ( agf->agf_anlist ) {
1659 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1660 int rc = test_filter( op, e, agf->agf_filter );
1661 if ( rc == LDAP_COMPARE_TRUE ) {
1662 age->age_modrdn_olddnmodified = 1;
1671 overlay_entry_release_ov( op, e, 0, on );
1672 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1673 return SLAP_CB_CONTINUE;
1677 ** Builds a filter for searching for the
1678 ** group entries, according to the objectClass.
1681 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1685 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1687 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1688 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1689 + agd->agd_oc->soc_cname.bv_len;
1690 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1692 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1694 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1698 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1700 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1711 static ConfigDriver ag_cfgen;
1713 static ConfigTable agcfg[] = {
1714 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1715 4, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1716 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1717 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1718 "EQUALITY caseIgnoreMatch "
1719 "SYNTAX OMsDirectoryString "
1720 "X-ORDERED 'VALUES' )",
1723 { "autogroup-memberof-ad", "memberOf attribute",
1724 2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen,
1725 "( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' "
1726 "DESC 'memberOf attribute' "
1727 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1730 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1733 static ConfigOCs agocs[] = {
1734 { "( OLcfgCtOc:2.1 "
1735 "NAME 'olcAutomaticGroups' "
1736 "DESC 'Automatic groups configuration' "
1737 "SUP olcOverlayConfig "
1740 "$ olcAGmemberOfAd "
1743 Cft_Overlay, agcfg, NULL, NULL },
1749 ag_cfgen( ConfigArgs *c )
1751 slap_overinst *on = (slap_overinst *)c->bi;
1752 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1753 autogroup_def_t *agd;
1754 autogroup_entry_t *age;
1758 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1761 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1762 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1763 agi->agi_def = NULL;
1764 agi->agi_entry = NULL;
1765 on->on_bi.bi_private = (void *)agi;
1769 age = agi->agi_entry;
1771 if ( c->op == SLAP_CONFIG_EMIT ) {
1775 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1777 char *ptr = c->cr_msg;
1779 assert(agd->agd_oc != NULL);
1780 assert(agd->agd_member_url_ad != NULL);
1781 assert(agd->agd_member_ad != NULL);
1783 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1784 SLAP_X_ORDERED_FMT "%s %s %s", i,
1785 agd->agd_oc->soc_cname.bv_val,
1786 agd->agd_member_url_ad->ad_cname.bv_val,
1787 agd->agd_member_ad->ad_cname.bv_val );
1789 bv.bv_val = c->cr_msg;
1790 bv.bv_len = ptr - bv.bv_val;
1791 value_add_one ( &c->rvalue_vals, &bv );
1796 case AG_MEMBER_OF_AD:
1797 if ( agi->agi_memberof_ad != NULL ){
1798 value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname );
1809 }else if ( c->op == LDAP_MOD_DELETE ) {
1811 autogroup_def_t *agd_next;
1812 autogroup_entry_t *age_next;
1813 autogroup_filter_t *agf = age->age_filter,
1816 for ( agd_next = agd; agd_next; agd = agd_next ) {
1817 agd_next = agd->agd_next;
1822 for ( age_next = age ; age_next ; age = age_next ) {
1823 age_next = age->age_next;
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;
1831 filter_free( agf->agf_filter );
1832 ch_free( agf->agf_filterstr.bv_val );
1833 ch_free( agf->agf_dn.bv_val );
1834 ch_free( agf->agf_ndn.bv_val );
1835 anlist_free( agf->agf_anlist, 1, NULL );
1839 ldap_pvt_thread_mutex_init( &age->age_mutex );
1844 on->on_bi.bi_private = NULL;
1847 autogroup_def_t **agdp;
1848 autogroup_entry_t *age_next, *age_prev;
1849 autogroup_filter_t *agf,
1852 for ( i = 0, agdp = &agi->agi_def;
1855 if ( *agdp == NULL) {
1858 agdp = &(*agdp)->agd_next;
1862 *agdp = agd->agd_next;
1864 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1865 age_next = age->age_next;
1867 if( age->age_def == agd ) {
1868 agf = age->age_filter;
1870 ch_free( age->age_dn.bv_val );
1871 ch_free( age->age_ndn.bv_val );
1873 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1874 agf_next = agf->agf_next;
1875 filter_free( agf->agf_filter );
1876 ch_free( agf->agf_filterstr.bv_val );
1877 ch_free( agf->agf_dn.bv_val );
1878 ch_free( agf->agf_ndn.bv_val );
1879 anlist_free( agf->agf_anlist, 1, NULL );
1883 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1888 if( age_prev != NULL ) {
1889 age_prev->age_next = age_next;
1904 autogroup_def_t **agdp,
1906 ObjectClass *oc = NULL;
1907 AttributeDescription *member_url_ad = NULL,
1912 oc = oc_find( c->argv[ 1 ] );
1914 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1915 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1916 "unable to find ObjectClass \"%s\"",
1918 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1919 c->log, c->cr_msg, 0 );
1924 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1925 if( rc != LDAP_SUCCESS ) {
1926 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1927 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1928 "unable to find AttributeDescription \"%s\"",
1930 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1931 c->log, c->cr_msg, 0 );
1935 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1936 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1937 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1938 "AttributeDescription \"%s\" ",
1939 "must be of a subtype \"labeledURI\"",
1941 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1942 c->log, c->cr_msg, 0 );
1946 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1947 if( rc != LDAP_SUCCESS ) {
1948 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1949 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1950 "unable to find AttributeDescription \"%s\"",
1952 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1953 c->log, c->cr_msg, 0 );
1957 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1958 /* The same URL attribute / member attribute pair
1959 * cannot be repeated */
1961 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1962 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1963 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1964 "URL attributeDescription \"%s\" already mapped",
1965 member_ad->ad_cname.bv_val );
1966 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1967 c->log, c->cr_msg, 0 );
1968 /* return 1; //warning*/
1972 if ( c->valx > 0 ) {
1975 for ( i = 0, agdp = &agi->agi_def ;
1978 if ( *agdp == NULL ) {
1979 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1980 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1981 "invalid index {%d}",
1983 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1984 c->log, c->cr_msg, 0 );
1988 agdp = &(*agdp)->agd_next;
1993 for ( agdp = &agi->agi_def; *agdp;
1994 agdp = &(*agdp)->agd_next )
1998 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
2000 (*agdp)->agd_oc = oc;
2001 (*agdp)->agd_member_url_ad = member_url_ad;
2002 (*agdp)->agd_member_ad = member_ad;
2003 (*agdp)->agd_next = agd_next;
2007 case AG_MEMBER_OF_AD: {
2008 AttributeDescription *memberof_ad = NULL;
2011 rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text );
2012 if( rc != LDAP_SUCCESS ) {
2013 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2014 "\"autogroup-memberof-ad <memberof-ad>\": "
2015 "unable to find AttributeDescription \"%s\"",
2017 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2018 c->log, c->cr_msg, 0 );
2022 if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */
2023 && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */
2025 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2026 "memberof attribute=\"%s\" must either "
2027 "have DN (%s) or nameUID (%s) syntax",
2028 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
2029 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2030 c->log, c->cr_msg, 0 );
2034 agi->agi_memberof_ad = memberof_ad;
2046 extern int slapMode;
2049 ** Do a search for all the groups in the
2050 ** database, and add them to out internal list.
2057 slap_overinst *on = (slap_overinst *) be->bd_info;
2058 autogroup_info_t *agi = on->on_bi.bi_private;
2059 autogroup_def_t *agd;
2062 slap_callback cb = { 0 };
2064 void *thrctx = ldap_pvt_thread_pool_context();
2065 Connection conn = { 0 };
2066 OperationBuffer opbuf;
2068 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
2070 if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
2074 connection_fake_init( &conn, &opbuf, thrctx );
2077 op->ors_attrsonly = 0;
2078 op->o_tag = LDAP_REQ_SEARCH;
2079 op->o_dn = be->be_rootdn;
2080 op->o_ndn = be->be_rootndn;
2082 op->o_req_dn = be->be_suffix[0];
2083 op->o_req_ndn = be->be_nsuffix[0];
2085 op->ors_scope = LDAP_SCOPE_SUBTREE;
2086 op->ors_deref = LDAP_DEREF_NEVER;
2087 op->ors_limit = NULL;
2088 op->ors_tlimit = SLAP_NO_LIMIT;
2089 op->ors_slimit = SLAP_NO_LIMIT;
2090 op->ors_attrs = slap_anlist_no_attrs;
2091 op->o_do_not_cache = 1;
2094 op->o_bd->bd_info = (BackendInfo *)on->on_info;
2097 cb.sc_private = &ags;
2098 cb.sc_response = autogroup_group_add_cb;
2099 cb.sc_cleanup = NULL;
2102 op->o_callback = &cb;
2104 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
2105 SlapReply rs = { REP_RESULT };
2107 autogroup_build_def_filter(agd, op);
2111 op->o_bd->be_search( op, &rs );
2113 filter_free_x( op, op->ors_filter, 1 );
2114 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
2117 if( ! agi->agi_memberof_ad ){
2119 const char *text = NULL;
2121 rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text );
2122 if ( rc != LDAP_SUCCESS ) {
2123 Debug( LDAP_DEBUG_ANY, "autogroup_db_open: "
2124 "unable to find attribute=\"%s\": %s (%d)\n",
2125 SLAPD_MEMBEROF_ATTR, text, rc );
2138 slap_overinst *on = (slap_overinst *) be->bd_info;
2140 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
2142 if ( on->on_bi.bi_private ) {
2143 autogroup_info_t *agi = on->on_bi.bi_private;
2144 autogroup_entry_t *age = agi->agi_entry,
2146 autogroup_filter_t *agf, *agf_next;
2148 for ( age_next = age; age_next; age = age_next ) {
2149 age_next = age->age_next;
2151 ch_free( age->age_dn.bv_val );
2152 ch_free( age->age_ndn.bv_val );
2154 agf = age->age_filter;
2156 for ( agf_next = agf; agf_next; agf = agf_next ) {
2157 agf_next = agf->agf_next;
2159 filter_free( agf->agf_filter );
2160 ch_free( agf->agf_filterstr.bv_val );
2161 ch_free( agf->agf_dn.bv_val );
2162 ch_free( agf->agf_ndn.bv_val );
2163 anlist_free( agf->agf_anlist, 1, NULL );
2167 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
2176 autogroup_db_destroy(
2180 slap_overinst *on = (slap_overinst *) be->bd_info;
2182 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
2184 if ( on->on_bi.bi_private ) {
2185 autogroup_info_t *agi = on->on_bi.bi_private;
2186 autogroup_def_t *agd = agi->agi_def,
2189 for ( agd_next = agd; agd_next; agd = agd_next ) {
2190 agd_next = agd->agd_next;
2195 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
2204 autogroup_initialize(void)
2207 autogroup.on_bi.bi_type = "autogroup";
2209 autogroup.on_bi.bi_db_open = autogroup_db_open;
2210 autogroup.on_bi.bi_db_close = autogroup_db_close;
2211 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
2213 autogroup.on_bi.bi_op_add = autogroup_add_entry;
2214 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
2215 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
2216 autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
2218 autogroup.on_response = autogroup_response;
2220 autogroup.on_bi.bi_cf_ocs = agocs;
2222 rc = config_register_schema( agcfg, agocs );
2227 return overlay_register( &autogroup );
2231 init_module( int argc, char *argv[] )
2233 return autogroup_initialize();