1 /* autogroup.c - automatic group overlay */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2007-2010 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:
28 #include <ac/string.h>
34 /* Filter represents the memberURL of a group. */
35 typedef struct autogroup_filter_t {
36 struct berval agf_dn; /* The base DN in memberURL */
37 struct berval agf_ndn;
38 struct berval agf_filterstr;
41 struct autogroup_filter_t *agf_next;
44 /* Description of group attributes. */
45 typedef struct autogroup_def_t {
47 AttributeDescription *agd_member_url_ad;
48 AttributeDescription *agd_member_ad;
49 struct autogroup_def_t *agd_next;
52 /* Represents the group entry. */
53 typedef struct autogroup_entry_t {
56 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
57 autogroup_def_t *age_def; /* Attribute definition */
58 ldap_pvt_thread_mutex_t age_mutex;
59 struct autogroup_entry_t *age_next;
62 /* Holds pointers to attribute definitions and groups. */
63 typedef struct autogroup_info_t {
64 autogroup_def_t *agi_def; /* Group attributes definitions. */
65 autogroup_entry_t *agi_entry; /* Group entries. */
66 ldap_pvt_thread_mutex_t agi_mutex;
69 /* Search callback for adding groups initially. */
70 typedef struct autogroup_sc_t {
71 autogroup_info_t *ags_info; /* Group definitions and entries. */
72 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
75 /* Used for adding members, found when searching, to a group. */
76 typedef struct autogroup_ga_t {
77 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
78 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
79 this entry with the search results. */
81 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
82 search results which will be added to the group. */
84 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
85 have to search for the last mod added. */
90 ** dn, ndn - the DN of the member to add
91 ** age - the group to which the member DN will be added
94 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
96 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
97 Modifications modlist;
98 SlapReply sreply = {REP_RESULT};
99 BerValue vals[ 2 ], nvals[ 2 ];
100 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
103 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
104 dn->bv_val, age->age_dn.bv_val, 0);
106 assert( dn != NULL );
107 assert( ndn != NULL );
110 BER_BVZERO( &vals[ 1 ] );
112 BER_BVZERO( &nvals[ 1 ] );
114 modlist.sml_op = LDAP_MOD_ADD;
115 modlist.sml_desc = age->age_def->agd_member_ad;
116 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
117 modlist.sml_values = vals;
118 modlist.sml_nvalues = nvals;
119 modlist.sml_numvals = 1;
120 modlist.sml_flags = SLAP_MOD_INTERNAL;
121 modlist.sml_next = NULL;
123 o.o_tag = LDAP_REQ_MODIFY;
125 o.orm_modlist = &modlist;
126 o.o_req_dn = age->age_dn;
127 o.o_req_ndn = age->age_ndn;
128 o.o_permissive_modify = 1;
129 o.o_managedsait = SLAP_CONTROL_CRITICAL;
130 o.o_relax = SLAP_CONTROL_CRITICAL;
132 o.o_bd->bd_info = (BackendInfo *)on->on_info;
133 (void)op->o_bd->be_modify( &o, &sreply );
134 o.o_bd->bd_info = (BackendInfo *)on;
136 return sreply.sr_err;
140 ** dn,ndn - the DN to be deleted
141 ** age - the group from which the DN will be deleted
142 ** If we pass a NULL dn and ndn, all members are deleted from the group.
145 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
147 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
148 Modifications modlist;
149 SlapReply sreply = {REP_RESULT};
150 BerValue vals[ 2 ], nvals[ 2 ];
151 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
154 if ( dn == NULL || ndn == NULL ) {
155 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
156 age->age_dn.bv_val, 0 ,0);
158 modlist.sml_values = NULL;
159 modlist.sml_nvalues = NULL;
160 modlist.sml_numvals = 0;
162 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
163 dn->bv_val, age->age_dn.bv_val, 0);
166 BER_BVZERO( &vals[ 1 ] );
168 BER_BVZERO( &nvals[ 1 ] );
170 modlist.sml_values = vals;
171 modlist.sml_nvalues = nvals;
172 modlist.sml_numvals = 1;
176 modlist.sml_op = LDAP_MOD_DELETE;
177 modlist.sml_desc = age->age_def->agd_member_ad;
178 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
179 modlist.sml_flags = SLAP_MOD_INTERNAL;
180 modlist.sml_next = NULL;
183 o.o_tag = LDAP_REQ_MODIFY;
184 o.orm_modlist = &modlist;
185 o.o_req_dn = age->age_dn;
186 o.o_req_ndn = age->age_ndn;
187 o.o_relax = SLAP_CONTROL_CRITICAL;
188 o.o_managedsait = SLAP_CONTROL_CRITICAL;
189 o.o_permissive_modify = 1;
191 o.o_bd->bd_info = (BackendInfo *)on->on_info;
192 (void)op->o_bd->be_modify( &o, &sreply );
193 o.o_bd->bd_info = (BackendInfo *)on;
195 return sreply.sr_err;
199 ** Callback used to add entries to a group,
200 ** which are going to be written in the database
201 ** (used in bi_op_add)
202 ** The group is passed in autogroup_ga_t->agg_group
205 autogroup_member_search_cb( Operation *op, SlapReply *rs )
207 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
209 assert( op->o_tag == LDAP_REQ_SEARCH );
211 if ( rs->sr_type == REP_SEARCH ) {
212 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
213 autogroup_entry_t *age = agg->agg_group;
215 const char *text = NULL;
217 struct berval vals[ 2 ], nvals[ 2 ];
219 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
220 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
222 vals[ 0 ] = rs->sr_entry->e_name;
223 BER_BVZERO( &vals[ 1 ] );
224 nvals[ 0 ] = rs->sr_entry->e_nname;
225 BER_BVZERO( &nvals[ 1 ] );
227 mod.sm_op = LDAP_MOD_ADD;
228 mod.sm_desc = age->age_def->agd_member_ad;
229 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
230 mod.sm_values = vals;
231 mod.sm_nvalues = nvals;
234 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
241 ** Callback used to add entries to a group, which is already in the database.
242 ** (used in on_response)
243 ** The group is passed in autogroup_ga_t->agg_group
247 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
249 assert( op->o_tag == LDAP_REQ_SEARCH );
251 if ( rs->sr_type == REP_SEARCH ) {
252 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
253 autogroup_entry_t *age = agg->agg_group;
254 Modifications *modlist;
255 struct berval vals[ 2 ], nvals[ 2 ];
257 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
258 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
260 vals[ 0 ] = rs->sr_entry->e_name;
261 BER_BVZERO( &vals[ 1 ] );
262 nvals[ 0 ] = rs->sr_entry->e_nname;
263 BER_BVZERO( &nvals[ 1 ] );
265 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
267 modlist->sml_op = LDAP_MOD_ADD;
268 modlist->sml_desc = age->age_def->agd_member_ad;
269 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
271 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
272 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
273 modlist->sml_numvals = 1;
275 modlist->sml_flags = SLAP_MOD_INTERNAL;
276 modlist->sml_next = NULL;
278 if ( agg->agg_mod == NULL ) {
279 agg->agg_mod = modlist;
280 agg->agg_mod_last = modlist;
282 agg->agg_mod_last->sml_next = modlist;
283 agg->agg_mod_last = modlist;
293 ** Adds all entries matching the passed filter to the specified group.
294 ** If modify == 1, then we modify the group's entry in the database using be_modify.
295 ** If modify == 0, then, we must supply a rw entry for the group,
296 ** because we only modify the entry, without calling be_modify.
297 ** e - the group entry, to which the members will be added
302 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
304 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
306 SlapReply rs = { REP_SEARCH };
307 slap_callback cb = { 0 };
308 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
311 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
312 age->age_dn.bv_val, 0, 0);
315 o.o_tag = LDAP_REQ_SEARCH;
317 o.o_req_dn = agf->agf_dn;
318 o.o_req_ndn = agf->agf_ndn;
320 o.ors_filterstr = agf->agf_filterstr;
321 o.ors_filter = agf->agf_filter;
323 o.ors_scope = agf->agf_scope;
324 o.ors_deref = LDAP_DEREF_NEVER;
326 o.ors_tlimit = SLAP_NO_LIMIT;
327 o.ors_slimit = SLAP_NO_LIMIT;
328 o.ors_attrs = slap_anlist_no_attrs;
332 agg.agg_mod_last = NULL;
334 cb.sc_private = &agg;
337 cb.sc_response = autogroup_member_search_modify_cb;
339 cb.sc_response = autogroup_member_search_cb;
342 cb.sc_cleanup = NULL;
347 o.o_bd->bd_info = (BackendInfo *)on->on_info;
348 op->o_bd->be_search( &o, &rs );
349 o.o_bd->bd_info = (BackendInfo *)on;
353 o.o_callback = &null_cb;
354 o.o_tag = LDAP_REQ_MODIFY;
355 o.orm_modlist = agg.agg_mod;
356 o.o_req_dn = age->age_dn;
357 o.o_req_ndn = age->age_ndn;
358 o.o_relax = SLAP_CONTROL_CRITICAL;
359 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
360 o.o_permissive_modify = 1;
362 o.o_bd->bd_info = (BackendInfo *)on->on_info;
363 (void)op->o_bd->be_modify( &o, &rs );
364 o.o_bd->bd_info = (BackendInfo *)on;
366 slap_mods_free(agg.agg_mod, 1);
373 ** Adds a group to the internal list from the passed entry.
374 ** scan specifies whether to add all maching members to the group.
375 ** modify specifies whether to modify the given group entry (when modify == 0),
376 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
377 ** agi - pointer to the groups and the attribute definitions
378 ** agd - the attribute definition of the added group
379 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
380 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
383 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
385 autogroup_entry_t **agep = &agi->agi_entry;
386 autogroup_filter_t *agf, *agf_prev = NULL;
387 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
388 LDAPURLDesc *lud = NULL;
391 int rc = 0, match = 1, null_entry = 0;
394 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
395 LDAP_SUCCESS || e == NULL ) {
396 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
403 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
404 e->e_name.bv_val, 0, 0);
406 if ( agi->agi_entry != NULL ) {
407 for ( ; *agep ; agep = &(*agep)->age_next ) {
408 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
410 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
418 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
419 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
420 (*agep)->age_def = agd;
421 (*agep)->age_filter = NULL;
423 ber_dupbv( &(*agep)->age_dn, &e->e_name );
424 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
426 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
428 if ( null_entry == 1 ) {
430 overlay_entry_release_ov( op, e, 0, on );
434 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
436 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
438 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
440 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
441 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
447 agf->agf_scope = lud->lud_scope;
449 if ( lud->lud_dn == NULL ) {
450 BER_BVSTR( &dn, "" );
452 ber_str2bv( lud->lud_dn, 0, 0, &dn );
455 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
456 if ( rc != LDAP_SUCCESS ) {
457 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
462 if ( lud->lud_filter != NULL ) {
463 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
464 agf->agf_filter = str2filter( lud->lud_filter );
467 agf->agf_next = NULL;
470 if( (*agep)->age_filter == NULL ) {
471 (*agep)->age_filter = agf;
474 if( agf_prev != NULL ) {
475 agf_prev->agf_next = agf;
481 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
484 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
485 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
487 ldap_free_urldesc( lud );
494 ldap_free_urldesc( lud );
499 if ( null_entry == 1 ) {
506 ** Used when opening the database to add all existing
507 ** groups from the database to our internal list.
510 autogroup_group_add_cb( Operation *op, SlapReply *rs )
512 assert( op->o_tag == LDAP_REQ_SEARCH );
514 if ( rs->sr_type == REP_SEARCH ) {
515 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
517 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
518 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
520 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
528 ** When adding a group, we first strip any existing members,
529 ** and add all which match the filters ourselfs.
532 autogroup_add_entry( Operation *op, SlapReply *rs)
534 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
535 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
536 autogroup_def_t *agd = agi->agi_def;
537 autogroup_entry_t *age = agi->agi_entry;
538 autogroup_filter_t *agf;
541 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
542 op->ora_e->e_name.bv_val, 0, 0);
544 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
546 /* Check if it's a group. */
547 for ( ; agd ; agd = agd->agd_next ) {
548 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
550 const char *text = NULL;
553 mod.sm_op = LDAP_MOD_DELETE;
554 mod.sm_desc = agd->agd_member_ad;
555 mod.sm_type = agd->agd_member_ad->ad_cname;
556 mod.sm_values = NULL;
557 mod.sm_nvalues = NULL;
559 /* We don't want any member attributes added by the user. */
560 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
562 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
563 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
564 return SLAP_CB_CONTINUE;
568 for ( ; age ; age = age->age_next ) {
569 ldap_pvt_thread_mutex_lock( &age->age_mutex );
571 /* Check if any of the filters are the suffix to the entry DN.
572 If yes, we can test that filter against the entry. */
574 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
575 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
576 rc = test_filter( op, op->ora_e, agf->agf_filter );
577 if ( rc == LDAP_COMPARE_TRUE ) {
578 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
583 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
586 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
588 return SLAP_CB_CONTINUE;
592 ** agi - internal group and attribute definitions list
593 ** e - the group to remove from the internal list
596 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
598 autogroup_entry_t *age = agi->agi_entry,
603 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
604 age->age_dn.bv_val, 0, 0);
606 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
607 age_next = age->age_next;
610 autogroup_filter_t *agf = age->age_filter,
613 if ( age_prev != NULL ) {
614 age_prev->age_next = age_next;
616 agi->agi_entry = NULL;
619 ch_free( age->age_dn.bv_val );
620 ch_free( age->age_ndn.bv_val );
622 for( agf_next = agf ; agf_next ; agf = agf_next ){
623 agf_next = agf->agf_next;
625 filter_free( agf->agf_filter );
626 ch_free( agf->agf_filterstr.bv_val );
627 ch_free( agf->agf_dn.bv_val );
628 ch_free( agf->agf_ndn.bv_val );
631 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
632 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
641 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
648 autogroup_delete_entry( Operation *op, SlapReply *rs)
650 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
651 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
652 autogroup_entry_t *age = agi->agi_entry,
653 *age_prev, *age_next;
654 autogroup_filter_t *agf;
656 int matched_group = 0, rc = 0;
658 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
660 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
662 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
663 LDAP_SUCCESS || e == NULL ) {
664 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
665 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
666 return SLAP_CB_CONTINUE;
669 /* Check if the entry to be deleted is one of our groups. */
670 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
671 ldap_pvt_thread_mutex_lock( &age->age_mutex );
672 age_next = age->age_next;
674 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
679 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
682 autogroup_delete_group( agi, age );
687 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
690 if ( matched_group == 1 ) {
691 overlay_entry_release_ov( op, e, 0, on );
692 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
693 return SLAP_CB_CONTINUE;
696 /* Check if the entry matches any of the groups.
697 If yes, we can delete the entry from that group. */
699 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
700 ldap_pvt_thread_mutex_lock( &age->age_mutex );
702 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
703 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
704 rc = test_filter( op, e, agf->agf_filter );
705 if ( rc == LDAP_COMPARE_TRUE ) {
706 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
711 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
714 overlay_entry_release_ov( op, e, 0, on );
715 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
717 return SLAP_CB_CONTINUE;
721 autogroup_response( Operation *op, SlapReply *rs )
723 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
724 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
725 autogroup_def_t *agd = agi->agi_def;
726 autogroup_entry_t *age = agi->agi_entry;
727 autogroup_filter_t *agf;
728 BerValue new_dn, new_ndn, pdn;
731 int is_olddn, is_newdn, dn_equal;
733 if ( op->o_tag == LDAP_REQ_MODRDN ) {
734 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
736 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
738 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
740 if ( op->oq_modrdn.rs_newSup ) {
741 pdn = *op->oq_modrdn.rs_newSup;
743 dnParent( &op->o_req_dn, &pdn );
745 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
747 if ( op->oq_modrdn.rs_nnewSup ) {
748 pdn = *op->oq_modrdn.rs_nnewSup;
750 dnParent( &op->o_req_ndn, &pdn );
752 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
754 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
756 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
758 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
759 LDAP_SUCCESS || e == NULL ) {
760 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
761 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
762 return SLAP_CB_CONTINUE;
765 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
769 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
770 overlay_entry_release_ov( op, e, 0, on );
771 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
772 return SLAP_CB_CONTINUE;
776 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
777 for ( ; agd; agd = agd->agd_next ) {
779 if ( value_find_ex( slap_schema.si_ad_objectClass,
780 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
781 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
782 a->a_nvals, &agd->agd_oc->soc_cname,
783 op->o_tmpmemctx ) == 0 )
785 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
788 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
790 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
791 ber_dupbv( &age->age_dn, &new_dn );
792 ber_dupbv( &age->age_ndn, &new_ndn );
794 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
795 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
796 overlay_entry_release_ov( op, e, 0, on );
797 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
798 return SLAP_CB_CONTINUE;
805 overlay_entry_release_ov( op, e, 0, on );
808 1. check if the orginal entry's DN is in the group.
809 2. chceck if the any of the group filter's base DN is a suffix of the new DN
811 If 1 and 2 are both false, we do nothing.
812 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
813 If 1 is false, and 2 is true, we check the entry against the group's filters,
814 and add it's DN to the group.
815 If 1 is true, and 2 is false, we delete the entry's DN from the group.
817 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
822 ldap_pvt_thread_mutex_lock( &age->age_mutex );
824 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
825 LDAP_SUCCESS || group == NULL ) {
826 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
828 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
829 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
831 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
832 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
833 return SLAP_CB_CONTINUE;
836 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
839 if ( value_find_ex( age->age_def->agd_member_ad,
840 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
841 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
842 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
849 overlay_entry_release_ov( op, group, 0, on );
851 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
852 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
859 if ( is_olddn == 1 && is_newdn == 0 ) {
860 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
862 if ( is_olddn == 0 && is_newdn == 1 ) {
863 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
864 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
865 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
870 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
871 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
872 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
875 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
878 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
879 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
881 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
885 if ( op->o_tag == LDAP_REQ_MODIFY ) {
886 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
887 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
889 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
891 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
892 LDAP_SUCCESS || e == NULL ) {
893 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
894 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
895 return SLAP_CB_CONTINUE;
898 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
902 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
903 overlay_entry_release_ov( op, e, 0, on );
904 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
905 return SLAP_CB_CONTINUE;
909 /* If we modify a group's memberURL, we have to delete all of it's members,
910 and add them anew, because we cannot tell from which memberURL a member was added. */
911 for ( ; agd; agd = agd->agd_next ) {
913 if ( value_find_ex( slap_schema.si_ad_objectClass,
914 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
915 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
916 a->a_nvals, &agd->agd_oc->soc_cname,
917 op->o_tmpmemctx ) == 0 )
924 for ( ; age ; age = age->age_next ) {
925 ldap_pvt_thread_mutex_lock( &age->age_mutex );
927 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
930 for ( ; m ; m = m->sml_next ) {
931 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
932 autogroup_def_t *group_agd = age->age_def;
933 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
934 op->o_req_dn.bv_val, 0, 0);
936 overlay_entry_release_ov( op, e, 0, on );
938 autogroup_delete_member_from_group( op, NULL, NULL, age );
939 autogroup_delete_group( agi, age );
941 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
943 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
944 return SLAP_CB_CONTINUE;
948 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
952 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
955 overlay_entry_release_ov( op, e, 0, on );
956 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
957 return SLAP_CB_CONTINUE;
961 overlay_entry_release_ov( op, e, 0, on );
963 /* When modifing any of the attributes of an entry, we must
964 check if the entry is in any of our groups, and if
965 the modified entry maches any of the filters of that group.
967 If the entry exists in a group, but the modified attributes do
968 not match any of the group's filters, we delete the entry from that group.
969 If the entry doesn't exist in a group, but matches a filter,
970 we add it to that group.
972 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
977 ldap_pvt_thread_mutex_lock( &age->age_mutex );
979 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
980 LDAP_SUCCESS || group == NULL ) {
981 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
982 age->age_dn.bv_val, 0, 0);
984 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
985 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
986 return SLAP_CB_CONTINUE;
989 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
992 if ( value_find_ex( age->age_def->agd_member_ad,
993 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
994 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
995 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1002 overlay_entry_release_ov( op, group, 0, on );
1004 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1005 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1006 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1013 if ( is_olddn == 1 && is_newdn == 0 ) {
1014 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1016 if ( is_olddn == 0 && is_newdn == 1 ) {
1017 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1020 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1023 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1027 return SLAP_CB_CONTINUE;
1031 ** When modifing a group, we must deny any modifications to the member attribute,
1032 ** because the group would be inconsistent.
1035 autogroup_modify_entry( Operation *op, SlapReply *rs)
1037 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1038 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1039 autogroup_def_t *agd = agi->agi_def;
1040 autogroup_entry_t *age = agi->agi_entry;
1044 if ( get_manageDSAit( op ) ) {
1045 return SLAP_CB_CONTINUE;
1048 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1049 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1051 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1052 LDAP_SUCCESS || e == NULL ) {
1053 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1054 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1055 return SLAP_CB_CONTINUE;
1058 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1061 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1062 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1063 return SLAP_CB_CONTINUE;
1067 for ( ; agd; agd = agd->agd_next ) {
1069 if ( value_find_ex( slap_schema.si_ad_objectClass,
1070 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1071 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1072 a->a_nvals, &agd->agd_oc->soc_cname,
1073 op->o_tmpmemctx ) == 0 )
1078 m = op->orm_modlist;
1080 for ( ; age ; age = age->age_next ) {
1081 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1084 for ( ; m ; m = m->sml_next ) {
1085 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1086 overlay_entry_release_ov( op, e, 0, on );
1087 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1088 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1089 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1090 return LDAP_CONSTRAINT_VIOLATION;
1097 overlay_entry_release_ov( op, e, 0, on );
1098 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1099 return SLAP_CB_CONTINUE;
1103 overlay_entry_release_ov( op, e, 0, on );
1104 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1105 return SLAP_CB_CONTINUE;
1109 ** Builds a filter for searching for the
1110 ** group entries, according to the objectClass.
1113 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1117 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1119 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1120 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1121 + agd->agd_oc->soc_cname.bv_len;
1122 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1124 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1126 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1130 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1132 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1142 static ConfigDriver ag_cfgen;
1144 static ConfigTable agcfg[] = {
1145 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1146 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1147 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1148 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1149 "EQUALITY caseIgnoreMatch "
1150 "SYNTAX OMsDirectoryString "
1151 "X-ORDERED 'VALUES' )",
1153 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1156 static ConfigOCs agocs[] = {
1157 { "( OLcfgCtOc:2.1 "
1158 "NAME 'olcAutomaticGroups' "
1159 "DESC 'Automatic groups configuration' "
1160 "SUP olcOverlayConfig "
1161 "MAY olcAGattrSet )",
1162 Cft_Overlay, agcfg, NULL, NULL },
1168 ag_cfgen( ConfigArgs *c )
1170 slap_overinst *on = (slap_overinst *)c->bi;
1171 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1172 autogroup_def_t *agd;
1173 autogroup_entry_t *age;
1177 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1180 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1181 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1182 agi->agi_def = NULL;
1183 agi->agi_entry = NULL;
1184 on->on_bi.bi_private = (void *)agi;
1188 age = agi->agi_entry;
1190 if ( c->op == SLAP_CONFIG_EMIT ) {
1192 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1194 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1196 char *ptr = c->cr_msg;
1198 assert(agd->agd_oc != NULL);
1199 assert(agd->agd_member_url_ad != NULL);
1200 assert(agd->agd_member_ad != NULL);
1202 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1203 SLAP_X_ORDERED_FMT "%s %s %s", i,
1204 agd->agd_oc->soc_cname.bv_val,
1205 agd->agd_member_url_ad->ad_cname.bv_val,
1206 agd->agd_member_ad->ad_cname.bv_val );
1208 bv.bv_val = c->cr_msg;
1209 bv.bv_len = ptr - bv.bv_val;
1210 value_add_one ( &c->rvalue_vals, &bv );
1213 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1217 }else if ( c->op == LDAP_MOD_DELETE ) {
1219 autogroup_def_t *agd_next;
1220 autogroup_entry_t *age_next;
1221 autogroup_filter_t *agf = age->age_filter,
1224 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1226 for ( agd_next = agd; agd_next; agd = agd_next ) {
1227 agd_next = agd->agd_next;
1232 for ( age_next = age ; age_next ; age = age_next ) {
1233 age_next = age->age_next;
1235 ch_free( age->age_dn.bv_val );
1236 ch_free( age->age_ndn.bv_val );
1238 for( agf_next = agf ; agf_next ; agf = agf_next ){
1239 agf_next = agf->agf_next;
1241 filter_free( agf->agf_filter );
1242 ch_free( agf->agf_filterstr.bv_val );
1243 ch_free( agf->agf_dn.bv_val );
1244 ch_free( agf->agf_ndn.bv_val );
1247 ldap_pvt_thread_mutex_init( &age->age_mutex );
1251 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1253 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1255 on->on_bi.bi_private = NULL;
1258 autogroup_def_t **agdp;
1259 autogroup_entry_t *age_next, *age_prev;
1260 autogroup_filter_t *agf,
1263 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1265 for ( i = 0, agdp = &agi->agi_def;
1268 if ( *agdp == NULL) {
1271 agdp = &(*agdp)->agd_next;
1275 *agdp = agd->agd_next;
1277 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1278 age_next = age->age_next;
1280 if( age->age_def == agd ) {
1281 agf = age->age_filter;
1283 ch_free( age->age_dn.bv_val );
1284 ch_free( age->age_ndn.bv_val );
1286 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1287 agf_next = agf->agf_next;
1288 filter_free( agf->agf_filter );
1289 ch_free( agf->agf_filterstr.bv_val );
1290 ch_free( agf->agf_dn.bv_val );
1291 ch_free( agf->agf_ndn.bv_val );
1294 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1299 if( age_prev != NULL ) {
1300 age_prev->age_next = age_next;
1307 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1316 autogroup_def_t **agdp,
1318 ObjectClass *oc = NULL;
1319 AttributeDescription *member_url_ad = NULL,
1324 oc = oc_find( c->argv[ 1 ] );
1326 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1327 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1328 "unable to find ObjectClass \"%s\"",
1330 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1331 c->log, c->cr_msg, 0 );
1336 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1337 if( rc != LDAP_SUCCESS ) {
1338 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1339 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1340 "unable to find AttributeDescription \"%s\"",
1342 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1343 c->log, c->cr_msg, 0 );
1347 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1348 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1349 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1350 "AttributeDescription \"%s\" ",
1351 "must be of a subtype \"labeledURI\"",
1353 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1354 c->log, c->cr_msg, 0 );
1358 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1359 if( rc != LDAP_SUCCESS ) {
1360 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1361 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1362 "unable to find AttributeDescription \"%s\"",
1364 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1365 c->log, c->cr_msg, 0 );
1369 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1371 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1372 /* The same URL attribute / member attribute pair
1373 * cannot be repeated */
1375 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1376 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1377 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1378 "URL attributeDescription \"%s\" already mapped",
1379 member_ad->ad_cname.bv_val );
1380 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1381 c->log, c->cr_msg, 0 );
1382 /* return 1; //warning*/
1386 if ( c->valx > 0 ) {
1389 for ( i = 0, agdp = &agi->agi_def ;
1392 if ( *agdp == NULL ) {
1393 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1394 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1395 "invalid index {%d}",
1397 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1398 c->log, c->cr_msg, 0 );
1400 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1403 agdp = &(*agdp)->agd_next;
1408 for ( agdp = &agi->agi_def; *agdp;
1409 agdp = &(*agdp)->agd_next )
1413 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1415 (*agdp)->agd_oc = oc;
1416 (*agdp)->agd_member_url_ad = member_url_ad;
1417 (*agdp)->agd_member_ad = member_ad;
1418 (*agdp)->agd_next = agd_next;
1420 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1433 ** Do a search for all the groups in the
1434 ** database, and add them to out internal list.
1441 slap_overinst *on = (slap_overinst *) be->bd_info;
1442 autogroup_info_t *agi = on->on_bi.bi_private;
1443 autogroup_def_t *agd;
1446 SlapReply rs = { REP_RESULT };
1447 slap_callback cb = { 0 };
1449 void *thrctx = ldap_pvt_thread_pool_context();
1450 Connection conn = { 0 };
1451 OperationBuffer opbuf;
1453 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1455 if ( agi == NULL ) {
1459 connection_fake_init( &conn, &opbuf, thrctx );
1462 op->ors_attrsonly = 0;
1463 op->o_tag = LDAP_REQ_SEARCH;
1464 op->o_dn = be->be_rootdn;
1465 op->o_ndn = be->be_rootndn;
1467 op->o_req_dn = be->be_suffix[0];
1468 op->o_req_ndn = be->be_nsuffix[0];
1470 op->ors_scope = LDAP_SCOPE_SUBTREE;
1471 op->ors_deref = LDAP_DEREF_NEVER;
1472 op->ors_limit = NULL;
1473 op->ors_tlimit = SLAP_NO_LIMIT;
1474 op->ors_slimit = SLAP_NO_LIMIT;
1475 op->ors_attrs = slap_anlist_no_attrs;
1478 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1481 cb.sc_private = &ags;
1482 cb.sc_response = autogroup_group_add_cb;
1483 cb.sc_cleanup = NULL;
1486 op->o_callback = &cb;
1488 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1490 autogroup_build_def_filter(agd, op);
1494 op->o_bd->be_search( op, &rs );
1496 filter_free_x( op, op->ors_filter, 1 );
1497 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1508 slap_overinst *on = (slap_overinst *) be->bd_info;
1510 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1512 if ( on->on_bi.bi_private ) {
1513 autogroup_info_t *agi = on->on_bi.bi_private;
1514 autogroup_entry_t *age = agi->agi_entry,
1516 autogroup_filter_t *agf, *agf_next;
1518 for ( age_next = age; age_next; age = age_next ) {
1519 age_next = age->age_next;
1521 ch_free( age->age_dn.bv_val );
1522 ch_free( age->age_ndn.bv_val );
1524 agf = age->age_filter;
1526 for ( agf_next = agf; agf_next; agf = agf_next ) {
1527 agf_next = agf->agf_next;
1529 filter_free( agf->agf_filter );
1530 ch_free( agf->agf_filterstr.bv_val );
1531 ch_free( agf->agf_dn.bv_val );
1532 ch_free( agf->agf_ndn.bv_val );
1536 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1545 autogroup_db_destroy(
1549 slap_overinst *on = (slap_overinst *) be->bd_info;
1551 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1553 if ( on->on_bi.bi_private ) {
1554 autogroup_info_t *agi = on->on_bi.bi_private;
1555 autogroup_def_t *agd = agi->agi_def,
1558 for ( agd_next = agd; agd_next; agd = agd_next ) {
1559 agd_next = agd->agd_next;
1564 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1571 static slap_overinst autogroup = { { NULL } };
1575 autogroup_initialize(void)
1578 autogroup.on_bi.bi_type = "autogroup";
1580 autogroup.on_bi.bi_db_open = autogroup_db_open;
1581 autogroup.on_bi.bi_db_close = autogroup_db_close;
1582 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1584 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1585 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1586 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1588 autogroup.on_response = autogroup_response;
1590 autogroup.on_bi.bi_cf_ocs = agocs;
1592 rc = config_register_schema( agcfg, agocs );
1597 return overlay_register( &autogroup );
1601 init_module( int argc, char *argv[] )
1603 return autogroup_initialize();