1 /* autogroup.c - automatic group overlay */
4 * Copyright 2007 Michał Szulczyński.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
20 #include <ac/string.h>
26 /* Filter represents the memberURL of a group. */
27 typedef struct autogroup_filter_t {
28 struct berval agf_dn; /* The base DN in memberURL */
29 struct berval agf_ndn;
30 struct berval agf_filterstr;
33 struct autogroup_filter_t *agf_next;
36 /* Description of group attributes. */
37 typedef struct autogroup_def_t {
39 AttributeDescription *agd_member_url_ad;
40 AttributeDescription *agd_member_ad;
41 struct autogroup_def_t *agd_next;
44 /* Represents the group entry. */
45 typedef struct autogroup_entry_t {
48 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
49 autogroup_def_t *age_def; /* Attribute definition */
50 ldap_pvt_thread_mutex_t age_mutex;
51 struct autogroup_entry_t *age_next;
54 /* Holds pointers to attribute definitions and groups. */
55 typedef struct autogroup_info_t {
56 autogroup_def_t *agi_def; /* Group attributes definitions. */
57 autogroup_entry_t *agi_entry; /* Group entries. */
58 ldap_pvt_thread_mutex_t agi_mutex;
61 /* Search callback for adding groups initially. */
62 typedef struct autogroup_sc_t {
63 autogroup_info_t *ags_info; /* Group definitions and entries. */
64 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
67 /* Used for adding members, found when searching, to a group. */
68 typedef struct autogroup_ga_t {
69 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
70 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
71 this entry with the search results. */
73 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
74 search results which will be added to the group. */
76 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
77 have to search for the last mod added. */
82 ** dn, ndn - the DN of the member to add
83 ** age - the group to which the member DN will be added
86 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
88 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
89 Modifications modlist;
90 SlapReply sreply = {REP_RESULT};
91 BerValue vals[ 2 ], nvals[ 2 ];
92 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
95 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
96 dn->bv_val, age->age_dn.bv_val, 0);
99 assert( ndn != NULL );
102 BER_BVZERO( &vals[ 1 ] );
104 BER_BVZERO( &nvals[ 1 ] );
106 modlist.sml_op = LDAP_MOD_ADD;
107 modlist.sml_desc = age->age_def->agd_member_ad;
108 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
109 modlist.sml_values = vals;
110 modlist.sml_nvalues = nvals;
111 modlist.sml_numvals = 1;
112 modlist.sml_flags = SLAP_MOD_INTERNAL;
113 modlist.sml_next = NULL;
115 o.o_tag = LDAP_REQ_MODIFY;
117 o.orm_modlist = &modlist;
118 o.o_req_dn = age->age_dn;
119 o.o_req_ndn = age->age_ndn;
120 o.o_permissive_modify = 1;
121 o.o_managedsait = SLAP_CONTROL_CRITICAL;
122 o.o_relax = SLAP_CONTROL_CRITICAL;
124 o.o_bd->bd_info = (BackendInfo *)on->on_info;
125 (void)op->o_bd->be_modify( &o, &sreply );
126 o.o_bd->bd_info = (BackendInfo *)on;
128 return sreply.sr_err;
132 ** dn,ndn - the DN to be deleted
133 ** age - the group from which the DN will be deleted
134 ** If we pass a NULL dn and ndn, all members are deleted from the group.
137 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
139 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
140 Modifications modlist;
141 SlapReply sreply = {REP_RESULT};
142 BerValue vals[ 2 ], nvals[ 2 ];
143 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
146 if ( dn == NULL || ndn == NULL ) {
147 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
148 age->age_dn.bv_val, 0 ,0);
150 modlist.sml_values = NULL;
151 modlist.sml_nvalues = NULL;
152 modlist.sml_numvals = 0;
154 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
155 dn->bv_val, age->age_dn.bv_val, 0);
158 BER_BVZERO( &vals[ 1 ] );
160 BER_BVZERO( &nvals[ 1 ] );
162 modlist.sml_values = vals;
163 modlist.sml_nvalues = nvals;
164 modlist.sml_numvals = 1;
168 modlist.sml_op = LDAP_MOD_DELETE;
169 modlist.sml_desc = age->age_def->agd_member_ad;
170 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
171 modlist.sml_flags = SLAP_MOD_INTERNAL;
172 modlist.sml_next = NULL;
175 o.o_tag = LDAP_REQ_MODIFY;
176 o.orm_modlist = &modlist;
177 o.o_req_dn = age->age_dn;
178 o.o_req_ndn = age->age_ndn;
179 o.o_relax = SLAP_CONTROL_CRITICAL;
180 o.o_managedsait = SLAP_CONTROL_CRITICAL;
181 o.o_permissive_modify = 1;
183 o.o_bd->bd_info = (BackendInfo *)on->on_info;
184 (void)op->o_bd->be_modify( &o, &sreply );
185 o.o_bd->bd_info = (BackendInfo *)on;
187 return sreply.sr_err;
191 ** Callback used to add entries to a group,
192 ** which are going to be written in the database
193 ** (used in bi_op_add)
194 ** The group is passed in autogroup_ga_t->agg_group
197 autogroup_member_search_cb( Operation *op, SlapReply *rs )
199 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
201 assert( op->o_tag == LDAP_REQ_SEARCH );
203 if ( rs->sr_type == REP_SEARCH ) {
204 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
205 autogroup_entry_t *age = agg->agg_group;
207 const char *text = NULL;
209 struct berval vals[ 2 ], nvals[ 2 ];
211 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
212 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
214 vals[ 0 ] = rs->sr_entry->e_name;
215 BER_BVZERO( &vals[ 1 ] );
216 nvals[ 0 ] = rs->sr_entry->e_nname;
217 BER_BVZERO( &nvals[ 1 ] );
219 mod.sm_op = LDAP_MOD_ADD;
220 mod.sm_desc = age->age_def->agd_member_ad;
221 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
222 mod.sm_values = vals;
223 mod.sm_nvalues = nvals;
226 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
233 ** Callback used to add entries to a group, which is already in the database.
234 ** (used in on_response)
235 ** The group is passed in autogroup_ga_t->agg_group
239 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
241 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
243 assert( op->o_tag == LDAP_REQ_SEARCH );
245 if ( rs->sr_type == REP_SEARCH ) {
246 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
247 autogroup_entry_t *age = agg->agg_group;
249 Modifications *modlist;
250 SlapReply sreply = {REP_RESULT};
251 const char *text = NULL;
253 struct berval vals[ 2 ], nvals[ 2 ];
254 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
256 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
257 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
259 vals[ 0 ] = rs->sr_entry->e_name;
260 BER_BVZERO( &vals[ 1 ] );
261 nvals[ 0 ] = rs->sr_entry->e_nname;
262 BER_BVZERO( &nvals[ 1 ] );
264 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
266 modlist->sml_op = LDAP_MOD_ADD;
267 modlist->sml_desc = age->age_def->agd_member_ad;
268 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
270 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
271 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
272 modlist->sml_numvals = 1;
274 modlist->sml_flags = SLAP_MOD_INTERNAL;
275 modlist->sml_next = NULL;
277 if ( agg->agg_mod == NULL ) {
278 agg->agg_mod = modlist;
279 agg->agg_mod_last = modlist;
281 agg->agg_mod_last->sml_next = modlist;
282 agg->agg_mod_last = modlist;
292 ** Adds all entries matching the passed filter to the specified group.
293 ** If modify == 1, then we modify the group's entry in the database using be_modify.
294 ** If modify == 0, then, we must supply a rw entry for the group,
295 ** because we only modify the entry, without calling be_modify.
296 ** e - the group entry, to which the members will be added
301 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
303 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
305 SlapReply rs = { REP_SEARCH };
306 slap_callback cb = { 0 };
307 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
310 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
311 age->age_dn.bv_val, 0, 0);
314 o.o_tag = LDAP_REQ_SEARCH;
316 o.o_req_dn = agf->agf_dn;
317 o.o_req_ndn = agf->agf_ndn;
319 o.ors_filterstr = agf->agf_filterstr;
320 o.ors_filter = agf->agf_filter;
322 o.ors_scope = agf->agf_scope;
323 o.ors_deref = LDAP_DEREF_NEVER;
325 o.ors_tlimit = SLAP_NO_LIMIT;
326 o.ors_slimit = SLAP_NO_LIMIT;
327 o.ors_attrs = slap_anlist_no_attrs;
331 agg.agg_mod_last = NULL;
333 cb.sc_private = &agg;
336 cb.sc_response = autogroup_member_search_modify_cb;
338 cb.sc_response = autogroup_member_search_cb;
341 cb.sc_cleanup = NULL;
346 o.o_bd->bd_info = (BackendInfo *)on->on_info;
347 op->o_bd->be_search( &o, &rs );
348 o.o_bd->bd_info = (BackendInfo *)on;
352 o.o_callback = &null_cb;
353 o.o_tag = LDAP_REQ_MODIFY;
354 o.orm_modlist = agg.agg_mod;
355 o.o_req_dn = age->age_dn;
356 o.o_req_ndn = age->age_ndn;
357 o.o_relax = SLAP_CONTROL_CRITICAL;
358 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
359 o.o_permissive_modify = 1;
361 o.o_bd->bd_info = (BackendInfo *)on->on_info;
362 (void)op->o_bd->be_modify( &o, &rs );
363 o.o_bd->bd_info = (BackendInfo *)on;
365 slap_mods_free(agg.agg_mod, 1);
372 ** Adds a group to the internal list from the passed entry.
373 ** scan specifies whether to add all maching members to the group.
374 ** modify specifies whether to modify the given group entry (when modify == 0),
375 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
376 ** agi - pointer to the groups and the attribute definitions
377 ** agd - the attribute definition of the added group
378 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
379 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
382 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
384 autogroup_entry_t **agep = &agi->agi_entry;
385 autogroup_filter_t *agf, *agf_prev = NULL;
386 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
387 LDAPURLDesc *lud = NULL;
390 int rc = 0, match = 1, null_entry = 0;
393 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
394 LDAP_SUCCESS || e == NULL ) {
395 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
402 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
403 e->e_name.bv_val, 0, 0);
405 if ( agi->agi_entry != NULL ) {
406 for ( ; *agep ; agep = &(*agep)->age_next ) {
407 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
409 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
417 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
418 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
419 (*agep)->age_def = agd;
420 (*agep)->age_filter = NULL;
422 ber_dupbv( &(*agep)->age_dn, &e->e_name );
423 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
425 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
427 if ( null_entry == 1 ) {
429 overlay_entry_release_ov( op, e, 0, on );
433 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
435 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
437 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
439 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
440 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
446 agf->agf_scope = lud->lud_scope;
448 if ( lud->lud_dn == NULL ) {
449 BER_BVSTR( &dn, "" );
451 ber_str2bv( lud->lud_dn, 0, 0, &dn );
454 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
455 if ( rc != LDAP_SUCCESS ) {
456 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
461 if ( lud->lud_filter != NULL ) {
462 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
463 agf->agf_filter = str2filter( lud->lud_filter );
466 agf->agf_next = NULL;
469 if( (*agep)->age_filter == NULL ) {
470 (*agep)->age_filter = agf;
473 if( agf_prev != NULL ) {
474 agf_prev->agf_next = agf;
480 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
483 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
484 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
486 ldap_free_urldesc( lud );
493 ldap_free_urldesc( lud );
498 if ( null_entry == 1 ) {
505 ** Used when opening the database to add all existing
506 ** groups from the database to our internal list.
509 autogroup_group_add_cb( Operation *op, SlapReply *rs )
511 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
513 assert( op->o_tag == LDAP_REQ_SEARCH );
516 if ( rs->sr_type == REP_SEARCH ) {
517 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
519 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
520 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
522 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
530 ** When adding a group, we first strip any existing members,
531 ** and add all which match the filters ourselfs.
534 autogroup_add_entry( Operation *op, SlapReply *rs)
536 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
537 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
538 autogroup_def_t *agd = agi->agi_def;
539 autogroup_entry_t *age = agi->agi_entry;
540 autogroup_filter_t *agf;
544 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
545 op->ora_e->e_name.bv_val, 0, 0);
547 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
549 /* Check if it's a group. */
550 for ( ; agd ; agd = agd->agd_next ) {
551 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
553 const char *text = NULL;
556 mod.sm_op = LDAP_MOD_DELETE;
557 mod.sm_desc = agd->agd_member_ad;
558 mod.sm_type = agd->agd_member_ad->ad_cname;
559 mod.sm_values = NULL;
560 mod.sm_nvalues = NULL;
562 /* We don't want any member attributes added by the user. */
563 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
565 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
566 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
567 return SLAP_CB_CONTINUE;
571 for ( ; age ; age = age->age_next ) {
572 ldap_pvt_thread_mutex_lock( &age->age_mutex );
574 /* Check if any of the filters are the suffix to the entry DN.
575 If yes, we can test that filter against the entry. */
577 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
578 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
579 rc = test_filter( op, op->ora_e, agf->agf_filter );
580 if ( rc == LDAP_COMPARE_TRUE ) {
581 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
586 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
589 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
591 return SLAP_CB_CONTINUE;
595 ** agi - internal group and attribute definitions list
596 ** e - the group to remove from the internal list
599 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
601 autogroup_entry_t *age = agi->agi_entry,
606 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
607 age->age_dn.bv_val, 0, 0);
609 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
610 age_next = age->age_next;
613 autogroup_filter_t *agf = age->age_filter,
616 if ( age_prev != NULL ) {
617 age_prev->age_next = age_next;
619 agi->agi_entry = NULL;
622 ch_free( age->age_dn.bv_val );
623 ch_free( age->age_ndn.bv_val );
625 for( agf_next = agf ; agf_next ; agf = agf_next ){
626 agf_next = agf->agf_next;
628 filter_free( agf->agf_filter );
629 ch_free( agf->agf_filterstr.bv_val );
630 ch_free( agf->agf_dn.bv_val );
631 ch_free( agf->agf_ndn.bv_val );
634 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
635 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
644 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
651 autogroup_delete_entry( Operation *op, SlapReply *rs)
653 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
654 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
655 autogroup_def_t *agd = agi->agi_def;
656 autogroup_entry_t *age = agi->agi_entry,
657 *age_prev, *age_next;
658 autogroup_filter_t *agf;
660 int matched_group = 0, rc = 0;
662 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
664 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
666 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
667 LDAP_SUCCESS || e == NULL ) {
668 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
669 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
670 return SLAP_CB_CONTINUE;
673 /* Check if the entry to be deleted is one of our groups. */
674 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
675 ldap_pvt_thread_mutex_lock( &age->age_mutex );
676 age_next = age->age_next;
678 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
683 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
686 autogroup_filter_t *agf = age->age_filter,
689 autogroup_delete_group( agi, age );
694 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
697 if ( matched_group == 1 ) {
698 overlay_entry_release_ov( op, e, 0, on );
699 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
700 return SLAP_CB_CONTINUE;
703 /* Check if the entry matches any of the groups.
704 If yes, we can delete the entry from that group. */
706 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
707 ldap_pvt_thread_mutex_lock( &age->age_mutex );
709 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
710 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
711 rc = test_filter( op, e, agf->agf_filter );
712 if ( rc == LDAP_COMPARE_TRUE ) {
713 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
718 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
721 overlay_entry_release_ov( op, e, 0, on );
722 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
724 return SLAP_CB_CONTINUE;
728 autogroup_response( Operation *op, SlapReply *rs )
730 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
731 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
732 autogroup_def_t *agd = agi->agi_def;
733 autogroup_entry_t *age = agi->agi_entry;
734 autogroup_filter_t *agf;
735 BerValue new_dn, new_ndn, pdn;
738 int is_olddn, is_newdn, dn_equal;
740 if ( op->o_tag == LDAP_REQ_MODRDN ) {
741 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
743 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
745 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
747 if ( op->oq_modrdn.rs_newSup ) {
748 pdn = *op->oq_modrdn.rs_newSup;
750 dnParent( &op->o_req_dn, &pdn );
752 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
754 if ( op->oq_modrdn.rs_nnewSup ) {
755 pdn = *op->oq_modrdn.rs_nnewSup;
757 dnParent( &op->o_req_ndn, &pdn );
759 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
761 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
763 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
765 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
766 LDAP_SUCCESS || e == NULL ) {
767 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
768 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
769 return SLAP_CB_CONTINUE;
772 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
776 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
777 overlay_entry_release_ov( op, e, 0, on );
778 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
779 return SLAP_CB_CONTINUE;
783 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
784 for ( ; agd; agd = agd->agd_next ) {
786 if ( value_find_ex( slap_schema.si_ad_objectClass,
787 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
788 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
789 a->a_nvals, &agd->agd_oc->soc_cname,
790 op->o_tmpmemctx ) == 0 )
792 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
795 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
797 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
798 ber_dupbv( &age->age_dn, &new_dn );
799 ber_dupbv( &age->age_ndn, &new_ndn );
801 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
802 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
803 overlay_entry_release_ov( op, e, 0, on );
804 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
805 return SLAP_CB_CONTINUE;
812 overlay_entry_release_ov( op, e, 0, on );
815 1. check if the orginal entry's DN is in the group.
816 2. chceck if the any of the group filter's base DN is a suffix of the new DN
818 If 1 and 2 are both false, we do nothing.
819 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
820 If 1 is false, and 2 is true, we check the entry against the group's filters,
821 and add it's DN to the group.
822 If 1 is true, and 2 is false, we delete the entry's DN from the group.
824 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
829 ldap_pvt_thread_mutex_lock( &age->age_mutex );
831 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
832 LDAP_SUCCESS || group == NULL ) {
833 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
835 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
836 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
838 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
839 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
840 return SLAP_CB_CONTINUE;
843 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
846 if ( value_find_ex( age->age_def->agd_member_ad,
847 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
848 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
849 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
856 overlay_entry_release_ov( op, group, 0, on );
858 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
859 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
866 if ( is_olddn == 1 && is_newdn == 0 ) {
867 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
869 if ( is_olddn == 0 && is_newdn == 1 ) {
870 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
871 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
872 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
877 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
878 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
879 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
882 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
885 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
886 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
888 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
892 if ( op->o_tag == LDAP_REQ_MODIFY ) {
893 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
894 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
896 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
898 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
899 LDAP_SUCCESS || e == NULL ) {
900 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
901 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
902 return SLAP_CB_CONTINUE;
905 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
909 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
910 overlay_entry_release_ov( op, e, 0, on );
911 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
912 return SLAP_CB_CONTINUE;
916 /* If we modify a group's memberURL, we have to delete all of it's members,
917 and add them anew, because we cannot tell from which memberURL a member was added. */
918 for ( ; agd; agd = agd->agd_next ) {
920 if ( value_find_ex( slap_schema.si_ad_objectClass,
921 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
922 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
923 a->a_nvals, &agd->agd_oc->soc_cname,
924 op->o_tmpmemctx ) == 0 )
931 for ( ; age ; age = age->age_next ) {
932 ldap_pvt_thread_mutex_lock( &age->age_mutex );
934 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
937 for ( ; m ; m = m->sml_next ) {
938 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
939 autogroup_def_t *group_agd = age->age_def;
940 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
941 op->o_req_dn.bv_val, 0, 0);
943 overlay_entry_release_ov( op, e, 0, on );
945 autogroup_delete_member_from_group( op, NULL, NULL, age );
946 autogroup_delete_group( agi, age );
948 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
950 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
951 return SLAP_CB_CONTINUE;
955 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
959 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
962 overlay_entry_release_ov( op, e, 0, on );
963 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
964 return SLAP_CB_CONTINUE;
968 overlay_entry_release_ov( op, e, 0, on );
970 /* When modifing any of the attributes of an entry, we must
971 check if the entry is in any of our groups, and if
972 the modified entry maches any of the filters of that group.
974 If the entry exists in a group, but the modified attributes do
975 not match any of the group's filters, we delete the entry from that group.
976 If the entry doesn't exist in a group, but matches a filter,
977 we add it to that group.
979 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
984 ldap_pvt_thread_mutex_lock( &age->age_mutex );
986 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
987 LDAP_SUCCESS || group == NULL ) {
988 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
989 age->age_dn.bv_val, 0, 0);
991 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
992 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
993 return SLAP_CB_CONTINUE;
996 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
999 if ( value_find_ex( age->age_def->agd_member_ad,
1000 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1001 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1002 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1009 overlay_entry_release_ov( op, group, 0, on );
1011 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1012 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1013 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1020 if ( is_olddn == 1 && is_newdn == 0 ) {
1021 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1023 if ( is_olddn == 0 && is_newdn == 1 ) {
1024 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1027 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1030 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1034 return SLAP_CB_CONTINUE;
1038 ** When modifing a group, we must deny any modifications to the member attribute,
1039 ** because the group would be inconsistent.
1042 autogroup_modify_entry( Operation *op, SlapReply *rs)
1044 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1045 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1046 autogroup_def_t *agd = agi->agi_def;
1047 autogroup_entry_t *age = agi->agi_entry;
1051 if ( get_manageDSAit( op ) ) {
1052 return SLAP_CB_CONTINUE;
1055 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1056 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1058 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1059 LDAP_SUCCESS || e == NULL ) {
1060 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1061 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1062 return SLAP_CB_CONTINUE;
1065 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1068 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1069 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1070 return SLAP_CB_CONTINUE;
1074 for ( ; agd; agd = agd->agd_next ) {
1076 if ( value_find_ex( slap_schema.si_ad_objectClass,
1077 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1078 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1079 a->a_nvals, &agd->agd_oc->soc_cname,
1080 op->o_tmpmemctx ) == 0 )
1085 m = op->orm_modlist;
1087 for ( ; age ; age = age->age_next ) {
1088 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1091 for ( ; m ; m = m->sml_next ) {
1092 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1093 overlay_entry_release_ov( op, e, 0, on );
1094 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1095 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1096 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1097 return LDAP_CONSTRAINT_VIOLATION;
1104 overlay_entry_release_ov( op, e, 0, on );
1105 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1106 return SLAP_CB_CONTINUE;
1110 overlay_entry_release_ov( op, e, 0, on );
1111 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1112 return SLAP_CB_CONTINUE;
1116 ** Builds a filter for searching for the
1117 ** group entries, according to the objectClass.
1120 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1124 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1126 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1127 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1128 + agd->agd_oc->soc_cname.bv_len;
1129 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1131 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1133 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1137 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1139 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1149 static ConfigDriver ag_cfgen;
1151 static ConfigTable agcfg[] = {
1152 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1153 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1154 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1155 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1156 "EQUALITY caseIgnoreMatch "
1157 "SYNTAX OMsDirectoryString "
1158 "X-ORDERED 'VALUES' )",
1160 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1163 static ConfigOCs agocs[] = {
1164 { "( OLcfgCtOc:2.1 "
1165 "NAME 'olcAutomaticGroups' "
1166 "DESC 'Automatic groups configuration' "
1167 "SUP olcOverlayConfig "
1168 "MAY olcAGattrSet )",
1169 Cft_Overlay, agcfg, NULL, NULL },
1175 ag_cfgen( ConfigArgs *c )
1177 slap_overinst *on = (slap_overinst *)c->bi;
1178 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1179 autogroup_def_t *agd;
1180 autogroup_entry_t *age;
1184 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1187 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1188 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1189 agi->agi_def = NULL;
1190 agi->agi_entry = NULL;
1191 on->on_bi.bi_private = (void *)agi;
1195 age = agi->agi_entry;
1197 if ( c->op == SLAP_CONFIG_EMIT ) {
1199 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1201 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1203 char *ptr = c->cr_msg;
1205 assert(agd->agd_oc != NULL);
1206 assert(agd->agd_member_url_ad != NULL);
1207 assert(agd->agd_member_ad != NULL);
1209 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1210 SLAP_X_ORDERED_FMT "%s %s %s", i,
1211 agd->agd_oc->soc_cname.bv_val,
1212 agd->agd_member_url_ad->ad_cname.bv_val,
1213 agd->agd_member_ad->ad_cname.bv_val );
1215 bv.bv_val = c->cr_msg;
1216 bv.bv_len = ptr - bv.bv_val;
1217 value_add_one ( &c->rvalue_vals, &bv );
1220 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1224 }else if ( c->op == LDAP_MOD_DELETE ) {
1226 autogroup_def_t *agd_next;
1227 autogroup_entry_t *age_next;
1228 autogroup_filter_t *agf = age->age_filter,
1231 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1233 for ( agd_next = agd; agd_next; agd = agd_next ) {
1234 agd_next = agd->agd_next;
1239 for ( age_next = age ; age_next ; age = age_next ) {
1240 age_next = age->age_next;
1242 ch_free( age->age_dn.bv_val );
1243 ch_free( age->age_ndn.bv_val );
1245 for( agf_next = agf ; agf_next ; agf = agf_next ){
1246 agf_next = agf->agf_next;
1248 filter_free( agf->agf_filter );
1249 ch_free( agf->agf_filterstr.bv_val );
1250 ch_free( agf->agf_dn.bv_val );
1251 ch_free( agf->agf_ndn.bv_val );
1254 ldap_pvt_thread_mutex_init( &age->age_mutex );
1258 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1260 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1262 on->on_bi.bi_private = NULL;
1265 autogroup_def_t **agdp;
1266 autogroup_entry_t *age_next, *age_prev;
1267 autogroup_filter_t *agf,
1271 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1273 for ( i = 0, agdp = &agi->agi_def;
1276 if ( *agdp == NULL) {
1279 agdp = &(*agdp)->agd_next;
1283 *agdp = agd->agd_next;
1285 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1286 age_next = age->age_next;
1288 if( age->age_def == agd ) {
1289 agf = age->age_filter;
1291 ch_free( age->age_dn.bv_val );
1292 ch_free( age->age_ndn.bv_val );
1294 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1295 agf_next = agf->agf_next;
1296 filter_free( agf->agf_filter );
1297 ch_free( agf->agf_filterstr.bv_val );
1298 ch_free( agf->agf_dn.bv_val );
1299 ch_free( agf->agf_ndn.bv_val );
1302 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1307 if( age_prev != NULL ) {
1308 age_prev->age_next = age_next;
1315 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1324 autogroup_def_t **agdp,
1326 ObjectClass *oc = NULL;
1327 AttributeDescription *member_url_ad = NULL,
1332 oc = oc_find( c->argv[ 1 ] );
1334 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1335 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1336 "unable to find ObjectClass \"%s\"",
1338 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1339 c->log, c->cr_msg, 0 );
1344 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1345 if( rc != LDAP_SUCCESS ) {
1346 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1347 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1348 "unable to find AttributeDescription \"%s\"",
1350 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1351 c->log, c->cr_msg, 0 );
1355 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1356 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1357 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1358 "AttributeDescription \"%s\" ",
1359 "must be of a subtype \"labeledURI\"",
1361 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1362 c->log, c->cr_msg, 0 );
1366 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1367 if( rc != LDAP_SUCCESS ) {
1368 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1369 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1370 "unable to find AttributeDescription \"%s\"",
1372 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1373 c->log, c->cr_msg, 0 );
1377 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1379 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1380 /* The same URL attribute / member attribute pair
1381 * cannot be repeated */
1383 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1384 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1385 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1386 "URL attributeDescription \"%s\" already mapped",
1387 member_ad->ad_cname.bv_val );
1388 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1389 c->log, c->cr_msg, 0 );
1390 /* return 1; //warning*/
1394 if ( c->valx > 0 ) {
1397 for ( i = 0, agdp = &agi->agi_def ;
1400 if ( *agdp == NULL ) {
1401 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1402 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1403 "invalid index {%d}",
1405 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1406 c->log, c->cr_msg, 0 );
1408 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1411 agdp = &(*agdp)->agd_next;
1416 for ( agdp = &agi->agi_def; *agdp;
1417 agdp = &(*agdp)->agd_next )
1421 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1423 (*agdp)->agd_oc = oc;
1424 (*agdp)->agd_member_url_ad = member_url_ad;
1425 (*agdp)->agd_member_ad = member_ad;
1426 (*agdp)->agd_next = agd_next;
1428 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1441 ** Do a search for all the groups in the
1442 ** database, and add them to out internal list.
1449 slap_overinst *on = (slap_overinst *) be->bd_info,
1451 autogroup_info_t *agi = on->on_bi.bi_private;
1452 autogroup_def_t *agd;
1455 SlapReply rs = { REP_RESULT };
1456 slap_callback cb = { 0 };
1458 void *thrctx = ldap_pvt_thread_pool_context();
1459 Connection conn = { 0 };
1460 OperationBuffer opbuf;
1465 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1467 connection_fake_init( &conn, &opbuf, thrctx );
1470 op->ors_attrsonly = 0;
1471 op->o_tag = LDAP_REQ_SEARCH;
1472 op->o_dn = be->be_rootdn;
1473 op->o_ndn = be->be_rootndn;
1475 op->o_req_dn = be->be_suffix[0];
1476 op->o_req_ndn = be->be_nsuffix[0];
1478 op->ors_scope = LDAP_SCOPE_SUBTREE;
1479 op->ors_deref = LDAP_DEREF_NEVER;
1480 op->ors_limit = NULL;
1481 op->ors_tlimit = SLAP_NO_LIMIT;
1482 op->ors_slimit = SLAP_NO_LIMIT;
1483 op->ors_attrs = slap_anlist_no_attrs;
1485 op->o_bd = select_backend(&op->o_req_ndn, 0);
1487 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1488 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1490 autogroup_build_def_filter(agd, op);
1495 cb.sc_private = &ags;
1496 cb.sc_response = autogroup_group_add_cb;
1497 cb.sc_cleanup = NULL;
1500 op->o_callback = &cb;
1502 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1503 op->o_bd->be_search( op, &rs );
1504 op->o_bd->bd_info = (BackendInfo *)on;
1506 filter_free_x( op, op->ors_filter );
1507 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1509 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1519 slap_overinst *on = (slap_overinst *) be->bd_info;
1521 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1523 if ( on->on_bi.bi_private ) {
1524 autogroup_info_t *agi = on->on_bi.bi_private;
1525 autogroup_entry_t *age = agi->agi_entry,
1527 autogroup_filter_t *agf, *agf_next;
1529 for ( age_next = age; age_next; age = age_next ) {
1530 age_next = age->age_next;
1532 ch_free( age->age_dn.bv_val );
1533 ch_free( age->age_ndn.bv_val );
1535 agf = age->age_filter;
1537 for ( agf_next = agf; agf_next; agf = agf_next ) {
1538 agf_next = agf->agf_next;
1540 filter_free( agf->agf_filter );
1541 ch_free( agf->agf_filterstr.bv_val );
1542 ch_free( agf->agf_dn.bv_val );
1543 ch_free( agf->agf_ndn.bv_val );
1547 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1556 autogroup_db_destroy(
1560 slap_overinst *on = (slap_overinst *) be->bd_info;
1562 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1564 if ( on->on_bi.bi_private ) {
1565 autogroup_info_t *agi = on->on_bi.bi_private;
1566 autogroup_def_t *agd = agi->agi_def,
1569 for ( agd_next = agd; agd_next; agd = agd_next ) {
1570 agd_next = agd->agd_next;
1575 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1582 static slap_overinst autogroup = { { NULL } };
1586 autogroup_initialize(void)
1589 autogroup.on_bi.bi_type = "autogroup";
1591 autogroup.on_bi.bi_db_open = autogroup_db_open;
1592 autogroup.on_bi.bi_db_close = autogroup_db_close;
1593 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1595 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1596 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1597 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1599 autogroup.on_response = autogroup_response;
1601 autogroup.on_bi.bi_cf_ocs = agocs;
1603 rc = config_register_schema( agcfg, agocs );
1608 return overlay_register( &autogroup );
1612 init_module( int argc, char *argv[] )
1614 return autogroup_initialize();