1 /* autogroup.c - automatic group overlay */
4 * Copyright 2007 Michał Szulczyński.
5 * Portions Copyright 2009 Howard Chu.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
21 #include <ac/string.h>
27 /* Filter represents the memberURL of a group. */
28 typedef struct autogroup_filter_t {
29 struct berval agf_dn; /* The base DN in memberURL */
30 struct berval agf_ndn;
31 struct berval agf_filterstr;
34 struct autogroup_filter_t *agf_next;
37 /* Description of group attributes. */
38 typedef struct autogroup_def_t {
40 AttributeDescription *agd_member_url_ad;
41 AttributeDescription *agd_member_ad;
42 struct autogroup_def_t *agd_next;
45 /* Represents the group entry. */
46 typedef struct autogroup_entry_t {
49 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
50 autogroup_def_t *age_def; /* Attribute definition */
51 ldap_pvt_thread_mutex_t age_mutex;
52 struct autogroup_entry_t *age_next;
55 /* Holds pointers to attribute definitions and groups. */
56 typedef struct autogroup_info_t {
57 autogroup_def_t *agi_def; /* Group attributes definitions. */
58 autogroup_entry_t *agi_entry; /* Group entries. */
59 ldap_pvt_thread_mutex_t agi_mutex;
62 /* Search callback for adding groups initially. */
63 typedef struct autogroup_sc_t {
64 autogroup_info_t *ags_info; /* Group definitions and entries. */
65 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
68 /* Used for adding members, found when searching, to a group. */
69 typedef struct autogroup_ga_t {
70 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
71 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
72 this entry with the search results. */
74 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
75 search results which will be added to the group. */
77 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
78 have to search for the last mod added. */
83 ** dn, ndn - the DN of the member to add
84 ** age - the group to which the member DN will be added
87 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
89 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
90 Modifications modlist;
91 SlapReply sreply = {REP_RESULT};
92 BerValue vals[ 2 ], nvals[ 2 ];
93 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
96 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
97 dn->bv_val, age->age_dn.bv_val, 0);
100 assert( ndn != NULL );
103 BER_BVZERO( &vals[ 1 ] );
105 BER_BVZERO( &nvals[ 1 ] );
107 modlist.sml_op = LDAP_MOD_ADD;
108 modlist.sml_desc = age->age_def->agd_member_ad;
109 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
110 modlist.sml_values = vals;
111 modlist.sml_nvalues = nvals;
112 modlist.sml_numvals = 1;
113 modlist.sml_flags = SLAP_MOD_INTERNAL;
114 modlist.sml_next = NULL;
116 o.o_tag = LDAP_REQ_MODIFY;
118 o.orm_modlist = &modlist;
119 o.o_req_dn = age->age_dn;
120 o.o_req_ndn = age->age_ndn;
121 o.o_permissive_modify = 1;
122 o.o_managedsait = SLAP_CONTROL_CRITICAL;
123 o.o_relax = SLAP_CONTROL_CRITICAL;
125 o.o_bd->bd_info = (BackendInfo *)on->on_info;
126 (void)op->o_bd->be_modify( &o, &sreply );
127 o.o_bd->bd_info = (BackendInfo *)on;
129 return sreply.sr_err;
133 ** dn,ndn - the DN to be deleted
134 ** age - the group from which the DN will be deleted
135 ** If we pass a NULL dn and ndn, all members are deleted from the group.
138 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
140 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
141 Modifications modlist;
142 SlapReply sreply = {REP_RESULT};
143 BerValue vals[ 2 ], nvals[ 2 ];
144 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
147 if ( dn == NULL || ndn == NULL ) {
148 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
149 age->age_dn.bv_val, 0 ,0);
151 modlist.sml_values = NULL;
152 modlist.sml_nvalues = NULL;
153 modlist.sml_numvals = 0;
155 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
156 dn->bv_val, age->age_dn.bv_val, 0);
159 BER_BVZERO( &vals[ 1 ] );
161 BER_BVZERO( &nvals[ 1 ] );
163 modlist.sml_values = vals;
164 modlist.sml_nvalues = nvals;
165 modlist.sml_numvals = 1;
169 modlist.sml_op = LDAP_MOD_DELETE;
170 modlist.sml_desc = age->age_def->agd_member_ad;
171 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
172 modlist.sml_flags = SLAP_MOD_INTERNAL;
173 modlist.sml_next = NULL;
176 o.o_tag = LDAP_REQ_MODIFY;
177 o.orm_modlist = &modlist;
178 o.o_req_dn = age->age_dn;
179 o.o_req_ndn = age->age_ndn;
180 o.o_relax = SLAP_CONTROL_CRITICAL;
181 o.o_managedsait = SLAP_CONTROL_CRITICAL;
182 o.o_permissive_modify = 1;
184 o.o_bd->bd_info = (BackendInfo *)on->on_info;
185 (void)op->o_bd->be_modify( &o, &sreply );
186 o.o_bd->bd_info = (BackendInfo *)on;
188 return sreply.sr_err;
192 ** Callback used to add entries to a group,
193 ** which are going to be written in the database
194 ** (used in bi_op_add)
195 ** The group is passed in autogroup_ga_t->agg_group
198 autogroup_member_search_cb( Operation *op, SlapReply *rs )
200 assert( op->o_tag == LDAP_REQ_SEARCH );
202 if ( rs->sr_type == REP_SEARCH ) {
203 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
204 autogroup_entry_t *age = agg->agg_group;
206 const char *text = NULL;
208 struct berval vals[ 2 ], nvals[ 2 ];
210 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
211 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
213 vals[ 0 ] = rs->sr_entry->e_name;
214 BER_BVZERO( &vals[ 1 ] );
215 nvals[ 0 ] = rs->sr_entry->e_nname;
216 BER_BVZERO( &nvals[ 1 ] );
218 mod.sm_op = LDAP_MOD_ADD;
219 mod.sm_desc = age->age_def->agd_member_ad;
220 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
221 mod.sm_values = vals;
222 mod.sm_nvalues = nvals;
225 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
232 ** Callback used to add entries to a group, which is already in the database.
233 ** (used in on_response)
234 ** The group is passed in autogroup_ga_t->agg_group
238 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
240 assert( op->o_tag == LDAP_REQ_SEARCH );
242 if ( rs->sr_type == REP_SEARCH ) {
243 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
244 autogroup_entry_t *age = agg->agg_group;
245 Modifications *modlist;
246 struct berval vals[ 2 ], nvals[ 2 ];
248 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
249 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
251 vals[ 0 ] = rs->sr_entry->e_name;
252 BER_BVZERO( &vals[ 1 ] );
253 nvals[ 0 ] = rs->sr_entry->e_nname;
254 BER_BVZERO( &nvals[ 1 ] );
256 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
258 modlist->sml_op = LDAP_MOD_ADD;
259 modlist->sml_desc = age->age_def->agd_member_ad;
260 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
262 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
263 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
264 modlist->sml_numvals = 1;
266 modlist->sml_flags = SLAP_MOD_INTERNAL;
267 modlist->sml_next = NULL;
269 if ( agg->agg_mod == NULL ) {
270 agg->agg_mod = modlist;
271 agg->agg_mod_last = modlist;
273 agg->agg_mod_last->sml_next = modlist;
274 agg->agg_mod_last = modlist;
284 ** Adds all entries matching the passed filter to the specified group.
285 ** If modify == 1, then we modify the group's entry in the database using be_modify.
286 ** If modify == 0, then, we must supply a rw entry for the group,
287 ** because we only modify the entry, without calling be_modify.
288 ** e - the group entry, to which the members will be added
293 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
295 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
297 SlapReply rs = { REP_SEARCH };
298 slap_callback cb = { 0 };
299 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
302 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
303 age->age_dn.bv_val, 0, 0);
306 o.o_tag = LDAP_REQ_SEARCH;
308 o.o_req_dn = agf->agf_dn;
309 o.o_req_ndn = agf->agf_ndn;
311 o.ors_filterstr = agf->agf_filterstr;
312 o.ors_filter = agf->agf_filter;
314 o.ors_scope = agf->agf_scope;
315 o.ors_deref = LDAP_DEREF_NEVER;
317 o.ors_tlimit = SLAP_NO_LIMIT;
318 o.ors_slimit = SLAP_NO_LIMIT;
319 o.ors_attrs = slap_anlist_no_attrs;
323 agg.agg_mod_last = NULL;
325 cb.sc_private = &agg;
328 cb.sc_response = autogroup_member_search_modify_cb;
330 cb.sc_response = autogroup_member_search_cb;
333 cb.sc_cleanup = NULL;
338 o.o_bd->bd_info = (BackendInfo *)on->on_info;
339 op->o_bd->be_search( &o, &rs );
340 o.o_bd->bd_info = (BackendInfo *)on;
344 o.o_callback = &null_cb;
345 o.o_tag = LDAP_REQ_MODIFY;
346 o.orm_modlist = agg.agg_mod;
347 o.o_req_dn = age->age_dn;
348 o.o_req_ndn = age->age_ndn;
349 o.o_relax = SLAP_CONTROL_CRITICAL;
350 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
351 o.o_permissive_modify = 1;
353 o.o_bd->bd_info = (BackendInfo *)on->on_info;
354 (void)op->o_bd->be_modify( &o, &rs );
355 o.o_bd->bd_info = (BackendInfo *)on;
357 slap_mods_free(agg.agg_mod, 1);
364 ** Adds a group to the internal list from the passed entry.
365 ** scan specifies whether to add all maching members to the group.
366 ** modify specifies whether to modify the given group entry (when modify == 0),
367 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
368 ** agi - pointer to the groups and the attribute definitions
369 ** agd - the attribute definition of the added group
370 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
371 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
374 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
376 autogroup_entry_t **agep = &agi->agi_entry;
377 autogroup_filter_t *agf, *agf_prev = NULL;
378 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
379 LDAPURLDesc *lud = NULL;
382 int rc = 0, match = 1, null_entry = 0;
385 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
386 LDAP_SUCCESS || e == NULL ) {
387 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
394 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
395 e->e_name.bv_val, 0, 0);
397 if ( agi->agi_entry != NULL ) {
398 for ( ; *agep ; agep = &(*agep)->age_next ) {
399 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
401 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
409 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
410 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
411 (*agep)->age_def = agd;
412 (*agep)->age_filter = NULL;
414 ber_dupbv( &(*agep)->age_dn, &e->e_name );
415 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
417 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
419 if ( null_entry == 1 ) {
421 overlay_entry_release_ov( op, e, 0, on );
425 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
427 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
429 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
431 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
432 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
438 agf->agf_scope = lud->lud_scope;
440 if ( lud->lud_dn == NULL ) {
441 BER_BVSTR( &dn, "" );
443 ber_str2bv( lud->lud_dn, 0, 0, &dn );
446 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
447 if ( rc != LDAP_SUCCESS ) {
448 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
453 if ( lud->lud_filter != NULL ) {
454 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
455 agf->agf_filter = str2filter( lud->lud_filter );
458 agf->agf_next = NULL;
461 if( (*agep)->age_filter == NULL ) {
462 (*agep)->age_filter = agf;
465 if( agf_prev != NULL ) {
466 agf_prev->agf_next = agf;
472 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
475 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
476 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
478 ldap_free_urldesc( lud );
485 ldap_free_urldesc( lud );
490 if ( null_entry == 1 ) {
497 ** Used when opening the database to add all existing
498 ** groups from the database to our internal list.
501 autogroup_group_add_cb( Operation *op, SlapReply *rs )
503 assert( op->o_tag == LDAP_REQ_SEARCH );
505 if ( rs->sr_type == REP_SEARCH ) {
506 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
508 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
509 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
511 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
519 ** When adding a group, we first strip any existing members,
520 ** and add all which match the filters ourselfs.
523 autogroup_add_entry( Operation *op, SlapReply *rs)
525 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
526 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
527 autogroup_def_t *agd = agi->agi_def;
528 autogroup_entry_t *age = agi->agi_entry;
529 autogroup_filter_t *agf;
532 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
533 op->ora_e->e_name.bv_val, 0, 0);
535 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
537 /* Check if it's a group. */
538 for ( ; agd ; agd = agd->agd_next ) {
539 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
541 const char *text = NULL;
544 mod.sm_op = LDAP_MOD_DELETE;
545 mod.sm_desc = agd->agd_member_ad;
546 mod.sm_type = agd->agd_member_ad->ad_cname;
547 mod.sm_values = NULL;
548 mod.sm_nvalues = NULL;
550 /* We don't want any member attributes added by the user. */
551 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
553 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
554 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
555 return SLAP_CB_CONTINUE;
559 for ( ; age ; age = age->age_next ) {
560 ldap_pvt_thread_mutex_lock( &age->age_mutex );
562 /* Check if any of the filters are the suffix to the entry DN.
563 If yes, we can test that filter against the entry. */
565 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
566 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
567 rc = test_filter( op, op->ora_e, agf->agf_filter );
568 if ( rc == LDAP_COMPARE_TRUE ) {
569 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
574 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
577 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
579 return SLAP_CB_CONTINUE;
583 ** agi - internal group and attribute definitions list
584 ** e - the group to remove from the internal list
587 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
589 autogroup_entry_t *age = agi->agi_entry,
594 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
595 age->age_dn.bv_val, 0, 0);
597 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
598 age_next = age->age_next;
601 autogroup_filter_t *agf = age->age_filter,
604 if ( age_prev != NULL ) {
605 age_prev->age_next = age_next;
607 agi->agi_entry = NULL;
610 ch_free( age->age_dn.bv_val );
611 ch_free( age->age_ndn.bv_val );
613 for( agf_next = agf ; agf_next ; agf = agf_next ){
614 agf_next = agf->agf_next;
616 filter_free( agf->agf_filter );
617 ch_free( agf->agf_filterstr.bv_val );
618 ch_free( agf->agf_dn.bv_val );
619 ch_free( agf->agf_ndn.bv_val );
622 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
623 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
632 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
639 autogroup_delete_entry( Operation *op, SlapReply *rs)
641 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
642 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
643 autogroup_entry_t *age = agi->agi_entry,
644 *age_prev, *age_next;
645 autogroup_filter_t *agf;
647 int matched_group = 0, rc = 0;
649 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
651 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
653 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
654 LDAP_SUCCESS || e == NULL ) {
655 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
656 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
657 return SLAP_CB_CONTINUE;
660 /* Check if the entry to be deleted is one of our groups. */
661 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
662 ldap_pvt_thread_mutex_lock( &age->age_mutex );
663 age_next = age->age_next;
665 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
670 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
673 autogroup_delete_group( agi, age );
678 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
681 if ( matched_group == 1 ) {
682 overlay_entry_release_ov( op, e, 0, on );
683 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
684 return SLAP_CB_CONTINUE;
687 /* Check if the entry matches any of the groups.
688 If yes, we can delete the entry from that group. */
690 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
691 ldap_pvt_thread_mutex_lock( &age->age_mutex );
693 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
694 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
695 rc = test_filter( op, e, agf->agf_filter );
696 if ( rc == LDAP_COMPARE_TRUE ) {
697 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
702 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
705 overlay_entry_release_ov( op, e, 0, on );
706 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
708 return SLAP_CB_CONTINUE;
712 autogroup_response( Operation *op, SlapReply *rs )
714 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
715 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
716 autogroup_def_t *agd = agi->agi_def;
717 autogroup_entry_t *age = agi->agi_entry;
718 autogroup_filter_t *agf;
719 BerValue new_dn, new_ndn, pdn;
722 int is_olddn, is_newdn, dn_equal;
724 if ( op->o_tag == LDAP_REQ_MODRDN ) {
725 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
727 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
729 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
731 if ( op->oq_modrdn.rs_newSup ) {
732 pdn = *op->oq_modrdn.rs_newSup;
734 dnParent( &op->o_req_dn, &pdn );
736 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
738 if ( op->oq_modrdn.rs_nnewSup ) {
739 pdn = *op->oq_modrdn.rs_nnewSup;
741 dnParent( &op->o_req_ndn, &pdn );
743 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
745 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
747 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
749 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
750 LDAP_SUCCESS || e == NULL ) {
751 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
752 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
753 return SLAP_CB_CONTINUE;
756 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
760 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
761 overlay_entry_release_ov( op, e, 0, on );
762 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
763 return SLAP_CB_CONTINUE;
767 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
768 for ( ; agd; agd = agd->agd_next ) {
770 if ( value_find_ex( slap_schema.si_ad_objectClass,
771 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
772 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
773 a->a_nvals, &agd->agd_oc->soc_cname,
774 op->o_tmpmemctx ) == 0 )
776 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
779 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
781 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
782 ber_dupbv( &age->age_dn, &new_dn );
783 ber_dupbv( &age->age_ndn, &new_ndn );
785 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
786 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
787 overlay_entry_release_ov( op, e, 0, on );
788 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
789 return SLAP_CB_CONTINUE;
796 overlay_entry_release_ov( op, e, 0, on );
799 1. check if the orginal entry's DN is in the group.
800 2. chceck if the any of the group filter's base DN is a suffix of the new DN
802 If 1 and 2 are both false, we do nothing.
803 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
804 If 1 is false, and 2 is true, we check the entry against the group's filters,
805 and add it's DN to the group.
806 If 1 is true, and 2 is false, we delete the entry's DN from the group.
808 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
813 ldap_pvt_thread_mutex_lock( &age->age_mutex );
815 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
816 LDAP_SUCCESS || group == NULL ) {
817 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
819 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
820 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
822 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
823 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
824 return SLAP_CB_CONTINUE;
827 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
830 if ( value_find_ex( age->age_def->agd_member_ad,
831 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
832 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
833 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
840 overlay_entry_release_ov( op, group, 0, on );
842 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
843 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
850 if ( is_olddn == 1 && is_newdn == 0 ) {
851 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
853 if ( is_olddn == 0 && is_newdn == 1 ) {
854 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
855 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
856 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
861 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
862 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
863 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
866 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
869 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
870 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
872 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
876 if ( op->o_tag == LDAP_REQ_MODIFY ) {
877 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
878 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
880 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
882 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
883 LDAP_SUCCESS || e == NULL ) {
884 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
885 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
886 return SLAP_CB_CONTINUE;
889 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
893 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
894 overlay_entry_release_ov( op, e, 0, on );
895 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
896 return SLAP_CB_CONTINUE;
900 /* If we modify a group's memberURL, we have to delete all of it's members,
901 and add them anew, because we cannot tell from which memberURL a member was added. */
902 for ( ; agd; agd = agd->agd_next ) {
904 if ( value_find_ex( slap_schema.si_ad_objectClass,
905 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
906 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
907 a->a_nvals, &agd->agd_oc->soc_cname,
908 op->o_tmpmemctx ) == 0 )
915 for ( ; age ; age = age->age_next ) {
916 ldap_pvt_thread_mutex_lock( &age->age_mutex );
918 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
921 for ( ; m ; m = m->sml_next ) {
922 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
923 autogroup_def_t *group_agd = age->age_def;
924 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
925 op->o_req_dn.bv_val, 0, 0);
927 overlay_entry_release_ov( op, e, 0, on );
929 autogroup_delete_member_from_group( op, NULL, NULL, age );
930 autogroup_delete_group( agi, age );
932 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
934 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
935 return SLAP_CB_CONTINUE;
939 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
943 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
946 overlay_entry_release_ov( op, e, 0, on );
947 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
948 return SLAP_CB_CONTINUE;
952 overlay_entry_release_ov( op, e, 0, on );
954 /* When modifing any of the attributes of an entry, we must
955 check if the entry is in any of our groups, and if
956 the modified entry maches any of the filters of that group.
958 If the entry exists in a group, but the modified attributes do
959 not match any of the group's filters, we delete the entry from that group.
960 If the entry doesn't exist in a group, but matches a filter,
961 we add it to that group.
963 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
968 ldap_pvt_thread_mutex_lock( &age->age_mutex );
970 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
971 LDAP_SUCCESS || group == NULL ) {
972 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
973 age->age_dn.bv_val, 0, 0);
975 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
976 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
977 return SLAP_CB_CONTINUE;
980 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
983 if ( value_find_ex( age->age_def->agd_member_ad,
984 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
985 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
986 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
993 overlay_entry_release_ov( op, group, 0, on );
995 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
996 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
997 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1004 if ( is_olddn == 1 && is_newdn == 0 ) {
1005 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1007 if ( is_olddn == 0 && is_newdn == 1 ) {
1008 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1011 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1014 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1018 return SLAP_CB_CONTINUE;
1022 ** When modifing a group, we must deny any modifications to the member attribute,
1023 ** because the group would be inconsistent.
1026 autogroup_modify_entry( Operation *op, SlapReply *rs)
1028 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1029 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1030 autogroup_def_t *agd = agi->agi_def;
1031 autogroup_entry_t *age = agi->agi_entry;
1035 if ( get_manageDSAit( op ) ) {
1036 return SLAP_CB_CONTINUE;
1039 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1040 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1042 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1043 LDAP_SUCCESS || e == NULL ) {
1044 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1045 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1046 return SLAP_CB_CONTINUE;
1049 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1052 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1053 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1054 return SLAP_CB_CONTINUE;
1058 for ( ; agd; agd = agd->agd_next ) {
1060 if ( value_find_ex( slap_schema.si_ad_objectClass,
1061 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1062 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1063 a->a_nvals, &agd->agd_oc->soc_cname,
1064 op->o_tmpmemctx ) == 0 )
1069 m = op->orm_modlist;
1071 for ( ; age ; age = age->age_next ) {
1072 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1075 for ( ; m ; m = m->sml_next ) {
1076 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1077 overlay_entry_release_ov( op, e, 0, on );
1078 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1079 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1080 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1081 return LDAP_CONSTRAINT_VIOLATION;
1088 overlay_entry_release_ov( op, e, 0, on );
1089 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1090 return SLAP_CB_CONTINUE;
1094 overlay_entry_release_ov( op, e, 0, on );
1095 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1096 return SLAP_CB_CONTINUE;
1100 ** Builds a filter for searching for the
1101 ** group entries, according to the objectClass.
1104 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1108 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1110 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1111 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1112 + agd->agd_oc->soc_cname.bv_len;
1113 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1115 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1117 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1121 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1123 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1133 static ConfigDriver ag_cfgen;
1135 static ConfigTable agcfg[] = {
1136 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1137 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1138 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1139 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1140 "EQUALITY caseIgnoreMatch "
1141 "SYNTAX OMsDirectoryString "
1142 "X-ORDERED 'VALUES' )",
1144 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1147 static ConfigOCs agocs[] = {
1148 { "( OLcfgCtOc:2.1 "
1149 "NAME 'olcAutomaticGroups' "
1150 "DESC 'Automatic groups configuration' "
1151 "SUP olcOverlayConfig "
1152 "MAY olcAGattrSet )",
1153 Cft_Overlay, agcfg, NULL, NULL },
1159 ag_cfgen( ConfigArgs *c )
1161 slap_overinst *on = (slap_overinst *)c->bi;
1162 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1163 autogroup_def_t *agd;
1164 autogroup_entry_t *age;
1168 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1171 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1172 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1173 agi->agi_def = NULL;
1174 agi->agi_entry = NULL;
1175 on->on_bi.bi_private = (void *)agi;
1179 age = agi->agi_entry;
1181 if ( c->op == SLAP_CONFIG_EMIT ) {
1183 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1185 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1187 char *ptr = c->cr_msg;
1189 assert(agd->agd_oc != NULL);
1190 assert(agd->agd_member_url_ad != NULL);
1191 assert(agd->agd_member_ad != NULL);
1193 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1194 SLAP_X_ORDERED_FMT "%s %s %s", i,
1195 agd->agd_oc->soc_cname.bv_val,
1196 agd->agd_member_url_ad->ad_cname.bv_val,
1197 agd->agd_member_ad->ad_cname.bv_val );
1199 bv.bv_val = c->cr_msg;
1200 bv.bv_len = ptr - bv.bv_val;
1201 value_add_one ( &c->rvalue_vals, &bv );
1204 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1208 }else if ( c->op == LDAP_MOD_DELETE ) {
1210 autogroup_def_t *agd_next;
1211 autogroup_entry_t *age_next;
1212 autogroup_filter_t *agf = age->age_filter,
1215 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1217 for ( agd_next = agd; agd_next; agd = agd_next ) {
1218 agd_next = agd->agd_next;
1223 for ( age_next = age ; age_next ; age = age_next ) {
1224 age_next = age->age_next;
1226 ch_free( age->age_dn.bv_val );
1227 ch_free( age->age_ndn.bv_val );
1229 for( agf_next = agf ; agf_next ; agf = agf_next ){
1230 agf_next = agf->agf_next;
1232 filter_free( agf->agf_filter );
1233 ch_free( agf->agf_filterstr.bv_val );
1234 ch_free( agf->agf_dn.bv_val );
1235 ch_free( agf->agf_ndn.bv_val );
1238 ldap_pvt_thread_mutex_init( &age->age_mutex );
1242 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1244 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1246 on->on_bi.bi_private = NULL;
1249 autogroup_def_t **agdp;
1250 autogroup_entry_t *age_next, *age_prev;
1251 autogroup_filter_t *agf,
1254 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1256 for ( i = 0, agdp = &agi->agi_def;
1259 if ( *agdp == NULL) {
1262 agdp = &(*agdp)->agd_next;
1266 *agdp = agd->agd_next;
1268 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1269 age_next = age->age_next;
1271 if( age->age_def == agd ) {
1272 agf = age->age_filter;
1274 ch_free( age->age_dn.bv_val );
1275 ch_free( age->age_ndn.bv_val );
1277 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1278 agf_next = agf->agf_next;
1279 filter_free( agf->agf_filter );
1280 ch_free( agf->agf_filterstr.bv_val );
1281 ch_free( agf->agf_dn.bv_val );
1282 ch_free( agf->agf_ndn.bv_val );
1285 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1290 if( age_prev != NULL ) {
1291 age_prev->age_next = age_next;
1298 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1307 autogroup_def_t **agdp,
1309 ObjectClass *oc = NULL;
1310 AttributeDescription *member_url_ad = NULL,
1315 oc = oc_find( c->argv[ 1 ] );
1317 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1318 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1319 "unable to find ObjectClass \"%s\"",
1321 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1322 c->log, c->cr_msg, 0 );
1327 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1328 if( rc != LDAP_SUCCESS ) {
1329 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1330 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1331 "unable to find AttributeDescription \"%s\"",
1333 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1334 c->log, c->cr_msg, 0 );
1338 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1339 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1340 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1341 "AttributeDescription \"%s\" ",
1342 "must be of a subtype \"labeledURI\"",
1344 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1345 c->log, c->cr_msg, 0 );
1349 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1350 if( rc != LDAP_SUCCESS ) {
1351 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1352 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1353 "unable to find AttributeDescription \"%s\"",
1355 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1356 c->log, c->cr_msg, 0 );
1360 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1362 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1363 /* The same URL attribute / member attribute pair
1364 * cannot be repeated */
1366 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1367 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1368 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1369 "URL attributeDescription \"%s\" already mapped",
1370 member_ad->ad_cname.bv_val );
1371 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1372 c->log, c->cr_msg, 0 );
1373 /* return 1; //warning*/
1377 if ( c->valx > 0 ) {
1380 for ( i = 0, agdp = &agi->agi_def ;
1383 if ( *agdp == NULL ) {
1384 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1385 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1386 "invalid index {%d}",
1388 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1389 c->log, c->cr_msg, 0 );
1391 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1394 agdp = &(*agdp)->agd_next;
1399 for ( agdp = &agi->agi_def; *agdp;
1400 agdp = &(*agdp)->agd_next )
1404 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1406 (*agdp)->agd_oc = oc;
1407 (*agdp)->agd_member_url_ad = member_url_ad;
1408 (*agdp)->agd_member_ad = member_ad;
1409 (*agdp)->agd_next = agd_next;
1411 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1424 ** Do a search for all the groups in the
1425 ** database, and add them to out internal list.
1432 slap_overinst *on = (slap_overinst *) be->bd_info;
1433 autogroup_info_t *agi = on->on_bi.bi_private;
1434 autogroup_def_t *agd;
1437 SlapReply rs = { REP_RESULT };
1438 slap_callback cb = { 0 };
1440 void *thrctx = ldap_pvt_thread_pool_context();
1441 Connection conn = { 0 };
1442 OperationBuffer opbuf;
1444 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1446 connection_fake_init( &conn, &opbuf, thrctx );
1449 op->ors_attrsonly = 0;
1450 op->o_tag = LDAP_REQ_SEARCH;
1451 op->o_dn = be->be_rootdn;
1452 op->o_ndn = be->be_rootndn;
1454 op->o_req_dn = be->be_suffix[0];
1455 op->o_req_ndn = be->be_nsuffix[0];
1457 op->ors_scope = LDAP_SCOPE_SUBTREE;
1458 op->ors_deref = LDAP_DEREF_NEVER;
1459 op->ors_limit = NULL;
1460 op->ors_tlimit = SLAP_NO_LIMIT;
1461 op->ors_slimit = SLAP_NO_LIMIT;
1462 op->ors_attrs = slap_anlist_no_attrs;
1465 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1468 cb.sc_private = &ags;
1469 cb.sc_response = autogroup_group_add_cb;
1470 cb.sc_cleanup = NULL;
1473 op->o_callback = &cb;
1475 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1477 autogroup_build_def_filter(agd, op);
1481 op->o_bd->be_search( op, &rs );
1483 filter_free_x( op, op->ors_filter, 1 );
1484 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1495 slap_overinst *on = (slap_overinst *) be->bd_info;
1497 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1499 if ( on->on_bi.bi_private ) {
1500 autogroup_info_t *agi = on->on_bi.bi_private;
1501 autogroup_entry_t *age = agi->agi_entry,
1503 autogroup_filter_t *agf, *agf_next;
1505 for ( age_next = age; age_next; age = age_next ) {
1506 age_next = age->age_next;
1508 ch_free( age->age_dn.bv_val );
1509 ch_free( age->age_ndn.bv_val );
1511 agf = age->age_filter;
1513 for ( agf_next = agf; agf_next; agf = agf_next ) {
1514 agf_next = agf->agf_next;
1516 filter_free( agf->agf_filter );
1517 ch_free( agf->agf_filterstr.bv_val );
1518 ch_free( agf->agf_dn.bv_val );
1519 ch_free( agf->agf_ndn.bv_val );
1523 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1532 autogroup_db_destroy(
1536 slap_overinst *on = (slap_overinst *) be->bd_info;
1538 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1540 if ( on->on_bi.bi_private ) {
1541 autogroup_info_t *agi = on->on_bi.bi_private;
1542 autogroup_def_t *agd = agi->agi_def,
1545 for ( agd_next = agd; agd_next; agd = agd_next ) {
1546 agd_next = agd->agd_next;
1551 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1558 static slap_overinst autogroup = { { NULL } };
1562 autogroup_initialize(void)
1565 autogroup.on_bi.bi_type = "autogroup";
1567 autogroup.on_bi.bi_db_open = autogroup_db_open;
1568 autogroup.on_bi.bi_db_close = autogroup_db_close;
1569 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1571 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1572 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1573 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1575 autogroup.on_response = autogroup_response;
1577 autogroup.on_bi.bi_cf_ocs = agocs;
1579 rc = config_register_schema( agcfg, agocs );
1584 return overlay_register( &autogroup );
1588 init_module( int argc, char *argv[] )
1590 return autogroup_initialize();