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 assert( op->o_tag == LDAP_REQ_SEARCH );
243 if ( rs->sr_type == REP_SEARCH ) {
244 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
245 autogroup_entry_t *age = agg->agg_group;
246 Modifications *modlist;
247 struct berval vals[ 2 ], nvals[ 2 ];
249 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
250 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
252 vals[ 0 ] = rs->sr_entry->e_name;
253 BER_BVZERO( &vals[ 1 ] );
254 nvals[ 0 ] = rs->sr_entry->e_nname;
255 BER_BVZERO( &nvals[ 1 ] );
257 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
259 modlist->sml_op = LDAP_MOD_ADD;
260 modlist->sml_desc = age->age_def->agd_member_ad;
261 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
263 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
264 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
265 modlist->sml_numvals = 1;
267 modlist->sml_flags = SLAP_MOD_INTERNAL;
268 modlist->sml_next = NULL;
270 if ( agg->agg_mod == NULL ) {
271 agg->agg_mod = modlist;
272 agg->agg_mod_last = modlist;
274 agg->agg_mod_last->sml_next = modlist;
275 agg->agg_mod_last = modlist;
285 ** Adds all entries matching the passed filter to the specified group.
286 ** If modify == 1, then we modify the group's entry in the database using be_modify.
287 ** If modify == 0, then, we must supply a rw entry for the group,
288 ** because we only modify the entry, without calling be_modify.
289 ** e - the group entry, to which the members will be added
294 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
296 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
298 SlapReply rs = { REP_SEARCH };
299 slap_callback cb = { 0 };
300 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
303 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
304 age->age_dn.bv_val, 0, 0);
307 o.o_tag = LDAP_REQ_SEARCH;
309 o.o_req_dn = agf->agf_dn;
310 o.o_req_ndn = agf->agf_ndn;
312 o.ors_filterstr = agf->agf_filterstr;
313 o.ors_filter = agf->agf_filter;
315 o.ors_scope = agf->agf_scope;
316 o.ors_deref = LDAP_DEREF_NEVER;
318 o.ors_tlimit = SLAP_NO_LIMIT;
319 o.ors_slimit = SLAP_NO_LIMIT;
320 o.ors_attrs = slap_anlist_no_attrs;
324 agg.agg_mod_last = NULL;
326 cb.sc_private = &agg;
329 cb.sc_response = autogroup_member_search_modify_cb;
331 cb.sc_response = autogroup_member_search_cb;
334 cb.sc_cleanup = NULL;
339 o.o_bd->bd_info = (BackendInfo *)on->on_info;
340 op->o_bd->be_search( &o, &rs );
341 o.o_bd->bd_info = (BackendInfo *)on;
345 o.o_callback = &null_cb;
346 o.o_tag = LDAP_REQ_MODIFY;
347 o.orm_modlist = agg.agg_mod;
348 o.o_req_dn = age->age_dn;
349 o.o_req_ndn = age->age_ndn;
350 o.o_relax = SLAP_CONTROL_CRITICAL;
351 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
352 o.o_permissive_modify = 1;
354 o.o_bd->bd_info = (BackendInfo *)on->on_info;
355 (void)op->o_bd->be_modify( &o, &rs );
356 o.o_bd->bd_info = (BackendInfo *)on;
358 slap_mods_free(agg.agg_mod, 1);
365 ** Adds a group to the internal list from the passed entry.
366 ** scan specifies whether to add all maching members to the group.
367 ** modify specifies whether to modify the given group entry (when modify == 0),
368 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
369 ** agi - pointer to the groups and the attribute definitions
370 ** agd - the attribute definition of the added group
371 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
372 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
375 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
377 autogroup_entry_t **agep = &agi->agi_entry;
378 autogroup_filter_t *agf, *agf_prev = NULL;
379 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
380 LDAPURLDesc *lud = NULL;
383 int rc = 0, match = 1, null_entry = 0;
386 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
387 LDAP_SUCCESS || e == NULL ) {
388 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
395 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
396 e->e_name.bv_val, 0, 0);
398 if ( agi->agi_entry != NULL ) {
399 for ( ; *agep ; agep = &(*agep)->age_next ) {
400 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
402 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
410 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
411 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
412 (*agep)->age_def = agd;
413 (*agep)->age_filter = NULL;
415 ber_dupbv( &(*agep)->age_dn, &e->e_name );
416 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
418 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
420 if ( null_entry == 1 ) {
422 overlay_entry_release_ov( op, e, 0, on );
426 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
428 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
430 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
432 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
433 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
439 agf->agf_scope = lud->lud_scope;
441 if ( lud->lud_dn == NULL ) {
442 BER_BVSTR( &dn, "" );
444 ber_str2bv( lud->lud_dn, 0, 0, &dn );
447 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
448 if ( rc != LDAP_SUCCESS ) {
449 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
454 if ( lud->lud_filter != NULL ) {
455 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
456 agf->agf_filter = str2filter( lud->lud_filter );
459 agf->agf_next = NULL;
462 if( (*agep)->age_filter == NULL ) {
463 (*agep)->age_filter = agf;
466 if( agf_prev != NULL ) {
467 agf_prev->agf_next = agf;
473 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
476 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
477 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
479 ldap_free_urldesc( lud );
486 ldap_free_urldesc( lud );
491 if ( null_entry == 1 ) {
498 ** Used when opening the database to add all existing
499 ** groups from the database to our internal list.
502 autogroup_group_add_cb( Operation *op, SlapReply *rs )
504 assert( op->o_tag == LDAP_REQ_SEARCH );
506 if ( rs->sr_type == REP_SEARCH ) {
507 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
509 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
510 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
512 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
520 ** When adding a group, we first strip any existing members,
521 ** and add all which match the filters ourselfs.
524 autogroup_add_entry( Operation *op, SlapReply *rs)
526 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
527 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
528 autogroup_def_t *agd = agi->agi_def;
529 autogroup_entry_t *age = agi->agi_entry;
530 autogroup_filter_t *agf;
533 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
534 op->ora_e->e_name.bv_val, 0, 0);
536 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
538 /* Check if it's a group. */
539 for ( ; agd ; agd = agd->agd_next ) {
540 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
542 const char *text = NULL;
545 mod.sm_op = LDAP_MOD_DELETE;
546 mod.sm_desc = agd->agd_member_ad;
547 mod.sm_type = agd->agd_member_ad->ad_cname;
548 mod.sm_values = NULL;
549 mod.sm_nvalues = NULL;
551 /* We don't want any member attributes added by the user. */
552 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
554 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
555 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
556 return SLAP_CB_CONTINUE;
560 for ( ; age ; age = age->age_next ) {
561 ldap_pvt_thread_mutex_lock( &age->age_mutex );
563 /* Check if any of the filters are the suffix to the entry DN.
564 If yes, we can test that filter against the entry. */
566 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
567 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
568 rc = test_filter( op, op->ora_e, agf->agf_filter );
569 if ( rc == LDAP_COMPARE_TRUE ) {
570 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
575 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
578 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
580 return SLAP_CB_CONTINUE;
584 ** agi - internal group and attribute definitions list
585 ** e - the group to remove from the internal list
588 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
590 autogroup_entry_t *age = agi->agi_entry,
595 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
596 age->age_dn.bv_val, 0, 0);
598 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
599 age_next = age->age_next;
602 autogroup_filter_t *agf = age->age_filter,
605 if ( age_prev != NULL ) {
606 age_prev->age_next = age_next;
608 agi->agi_entry = NULL;
611 ch_free( age->age_dn.bv_val );
612 ch_free( age->age_ndn.bv_val );
614 for( agf_next = agf ; agf_next ; agf = agf_next ){
615 agf_next = agf->agf_next;
617 filter_free( agf->agf_filter );
618 ch_free( agf->agf_filterstr.bv_val );
619 ch_free( agf->agf_dn.bv_val );
620 ch_free( agf->agf_ndn.bv_val );
623 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
624 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
633 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
640 autogroup_delete_entry( Operation *op, SlapReply *rs)
642 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
643 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
644 autogroup_entry_t *age = agi->agi_entry,
645 *age_prev, *age_next;
646 autogroup_filter_t *agf;
648 int matched_group = 0, rc = 0;
650 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
652 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
654 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
655 LDAP_SUCCESS || e == NULL ) {
656 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
657 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
658 return SLAP_CB_CONTINUE;
661 /* Check if the entry to be deleted is one of our groups. */
662 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
663 ldap_pvt_thread_mutex_lock( &age->age_mutex );
664 age_next = age->age_next;
666 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
671 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
674 autogroup_delete_group( agi, age );
679 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
682 if ( matched_group == 1 ) {
683 overlay_entry_release_ov( op, e, 0, on );
684 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
685 return SLAP_CB_CONTINUE;
688 /* Check if the entry matches any of the groups.
689 If yes, we can delete the entry from that group. */
691 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
692 ldap_pvt_thread_mutex_lock( &age->age_mutex );
694 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
695 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
696 rc = test_filter( op, e, agf->agf_filter );
697 if ( rc == LDAP_COMPARE_TRUE ) {
698 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
703 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
706 overlay_entry_release_ov( op, e, 0, on );
707 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
709 return SLAP_CB_CONTINUE;
713 autogroup_response( Operation *op, SlapReply *rs )
715 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
716 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
717 autogroup_def_t *agd = agi->agi_def;
718 autogroup_entry_t *age = agi->agi_entry;
719 autogroup_filter_t *agf;
720 BerValue new_dn, new_ndn, pdn;
723 int is_olddn, is_newdn, dn_equal;
725 if ( op->o_tag == LDAP_REQ_MODRDN ) {
726 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
728 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
730 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
732 if ( op->oq_modrdn.rs_newSup ) {
733 pdn = *op->oq_modrdn.rs_newSup;
735 dnParent( &op->o_req_dn, &pdn );
737 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
739 if ( op->oq_modrdn.rs_nnewSup ) {
740 pdn = *op->oq_modrdn.rs_nnewSup;
742 dnParent( &op->o_req_ndn, &pdn );
744 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
746 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
748 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
750 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
751 LDAP_SUCCESS || e == NULL ) {
752 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
753 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
754 return SLAP_CB_CONTINUE;
757 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
761 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
762 overlay_entry_release_ov( op, e, 0, on );
763 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
764 return SLAP_CB_CONTINUE;
768 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
769 for ( ; agd; agd = agd->agd_next ) {
771 if ( value_find_ex( slap_schema.si_ad_objectClass,
772 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
773 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
774 a->a_nvals, &agd->agd_oc->soc_cname,
775 op->o_tmpmemctx ) == 0 )
777 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
780 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
782 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
783 ber_dupbv( &age->age_dn, &new_dn );
784 ber_dupbv( &age->age_ndn, &new_ndn );
786 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
787 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
788 overlay_entry_release_ov( op, e, 0, on );
789 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
790 return SLAP_CB_CONTINUE;
797 overlay_entry_release_ov( op, e, 0, on );
800 1. check if the orginal entry's DN is in the group.
801 2. chceck if the any of the group filter's base DN is a suffix of the new DN
803 If 1 and 2 are both false, we do nothing.
804 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
805 If 1 is false, and 2 is true, we check the entry against the group's filters,
806 and add it's DN to the group.
807 If 1 is true, and 2 is false, we delete the entry's DN from the group.
809 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
814 ldap_pvt_thread_mutex_lock( &age->age_mutex );
816 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
817 LDAP_SUCCESS || group == NULL ) {
818 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
820 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
821 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
823 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
824 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
825 return SLAP_CB_CONTINUE;
828 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
831 if ( value_find_ex( age->age_def->agd_member_ad,
832 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
833 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
834 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
841 overlay_entry_release_ov( op, group, 0, on );
843 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
844 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
851 if ( is_olddn == 1 && is_newdn == 0 ) {
852 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
854 if ( is_olddn == 0 && is_newdn == 1 ) {
855 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
856 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
857 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
862 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
863 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
864 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
867 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
870 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
871 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
873 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
877 if ( op->o_tag == LDAP_REQ_MODIFY ) {
878 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
879 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
881 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
883 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
884 LDAP_SUCCESS || e == NULL ) {
885 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
886 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
887 return SLAP_CB_CONTINUE;
890 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
894 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
895 overlay_entry_release_ov( op, e, 0, on );
896 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
897 return SLAP_CB_CONTINUE;
901 /* If we modify a group's memberURL, we have to delete all of it's members,
902 and add them anew, because we cannot tell from which memberURL a member was added. */
903 for ( ; agd; agd = agd->agd_next ) {
905 if ( value_find_ex( slap_schema.si_ad_objectClass,
906 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
907 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
908 a->a_nvals, &agd->agd_oc->soc_cname,
909 op->o_tmpmemctx ) == 0 )
916 for ( ; age ; age = age->age_next ) {
917 ldap_pvt_thread_mutex_lock( &age->age_mutex );
919 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
922 for ( ; m ; m = m->sml_next ) {
923 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
924 autogroup_def_t *group_agd = age->age_def;
925 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
926 op->o_req_dn.bv_val, 0, 0);
928 overlay_entry_release_ov( op, e, 0, on );
930 autogroup_delete_member_from_group( op, NULL, NULL, age );
931 autogroup_delete_group( agi, age );
933 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
935 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
936 return SLAP_CB_CONTINUE;
940 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
944 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
947 overlay_entry_release_ov( op, e, 0, on );
948 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
949 return SLAP_CB_CONTINUE;
953 overlay_entry_release_ov( op, e, 0, on );
955 /* When modifing any of the attributes of an entry, we must
956 check if the entry is in any of our groups, and if
957 the modified entry maches any of the filters of that group.
959 If the entry exists in a group, but the modified attributes do
960 not match any of the group's filters, we delete the entry from that group.
961 If the entry doesn't exist in a group, but matches a filter,
962 we add it to that group.
964 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
969 ldap_pvt_thread_mutex_lock( &age->age_mutex );
971 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
972 LDAP_SUCCESS || group == NULL ) {
973 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
974 age->age_dn.bv_val, 0, 0);
976 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
977 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
978 return SLAP_CB_CONTINUE;
981 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
984 if ( value_find_ex( age->age_def->agd_member_ad,
985 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
986 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
987 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
994 overlay_entry_release_ov( op, group, 0, on );
996 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
997 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
998 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1005 if ( is_olddn == 1 && is_newdn == 0 ) {
1006 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1008 if ( is_olddn == 0 && is_newdn == 1 ) {
1009 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1012 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1015 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1019 return SLAP_CB_CONTINUE;
1023 ** When modifing a group, we must deny any modifications to the member attribute,
1024 ** because the group would be inconsistent.
1027 autogroup_modify_entry( Operation *op, SlapReply *rs)
1029 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1030 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1031 autogroup_def_t *agd = agi->agi_def;
1032 autogroup_entry_t *age = agi->agi_entry;
1036 if ( get_manageDSAit( op ) ) {
1037 return SLAP_CB_CONTINUE;
1040 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1041 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1043 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1044 LDAP_SUCCESS || e == NULL ) {
1045 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1046 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1047 return SLAP_CB_CONTINUE;
1050 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1053 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1054 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1055 return SLAP_CB_CONTINUE;
1059 for ( ; agd; agd = agd->agd_next ) {
1061 if ( value_find_ex( slap_schema.si_ad_objectClass,
1062 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1063 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1064 a->a_nvals, &agd->agd_oc->soc_cname,
1065 op->o_tmpmemctx ) == 0 )
1070 m = op->orm_modlist;
1072 for ( ; age ; age = age->age_next ) {
1073 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1076 for ( ; m ; m = m->sml_next ) {
1077 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1078 overlay_entry_release_ov( op, e, 0, on );
1079 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1080 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1081 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1082 return LDAP_CONSTRAINT_VIOLATION;
1089 overlay_entry_release_ov( op, e, 0, on );
1090 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1091 return SLAP_CB_CONTINUE;
1095 overlay_entry_release_ov( op, e, 0, on );
1096 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1097 return SLAP_CB_CONTINUE;
1101 ** Builds a filter for searching for the
1102 ** group entries, according to the objectClass.
1105 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1109 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1111 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1112 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1113 + agd->agd_oc->soc_cname.bv_len;
1114 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1116 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1118 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1122 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1124 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1134 static ConfigDriver ag_cfgen;
1136 static ConfigTable agcfg[] = {
1137 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1138 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1139 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1140 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1141 "EQUALITY caseIgnoreMatch "
1142 "SYNTAX OMsDirectoryString "
1143 "X-ORDERED 'VALUES' )",
1145 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1148 static ConfigOCs agocs[] = {
1149 { "( OLcfgCtOc:2.1 "
1150 "NAME 'olcAutomaticGroups' "
1151 "DESC 'Automatic groups configuration' "
1152 "SUP olcOverlayConfig "
1153 "MAY olcAGattrSet )",
1154 Cft_Overlay, agcfg, NULL, NULL },
1160 ag_cfgen( ConfigArgs *c )
1162 slap_overinst *on = (slap_overinst *)c->bi;
1163 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1164 autogroup_def_t *agd;
1165 autogroup_entry_t *age;
1169 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1172 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1173 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1174 agi->agi_def = NULL;
1175 agi->agi_entry = NULL;
1176 on->on_bi.bi_private = (void *)agi;
1180 age = agi->agi_entry;
1182 if ( c->op == SLAP_CONFIG_EMIT ) {
1184 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1186 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1188 char *ptr = c->cr_msg;
1190 assert(agd->agd_oc != NULL);
1191 assert(agd->agd_member_url_ad != NULL);
1192 assert(agd->agd_member_ad != NULL);
1194 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1195 SLAP_X_ORDERED_FMT "%s %s %s", i,
1196 agd->agd_oc->soc_cname.bv_val,
1197 agd->agd_member_url_ad->ad_cname.bv_val,
1198 agd->agd_member_ad->ad_cname.bv_val );
1200 bv.bv_val = c->cr_msg;
1201 bv.bv_len = ptr - bv.bv_val;
1202 value_add_one ( &c->rvalue_vals, &bv );
1205 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1209 }else if ( c->op == LDAP_MOD_DELETE ) {
1211 autogroup_def_t *agd_next;
1212 autogroup_entry_t *age_next;
1213 autogroup_filter_t *agf = age->age_filter,
1216 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1218 for ( agd_next = agd; agd_next; agd = agd_next ) {
1219 agd_next = agd->agd_next;
1224 for ( age_next = age ; age_next ; age = age_next ) {
1225 age_next = age->age_next;
1227 ch_free( age->age_dn.bv_val );
1228 ch_free( age->age_ndn.bv_val );
1230 for( agf_next = agf ; agf_next ; agf = agf_next ){
1231 agf_next = agf->agf_next;
1233 filter_free( agf->agf_filter );
1234 ch_free( agf->agf_filterstr.bv_val );
1235 ch_free( agf->agf_dn.bv_val );
1236 ch_free( agf->agf_ndn.bv_val );
1239 ldap_pvt_thread_mutex_init( &age->age_mutex );
1243 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1245 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1247 on->on_bi.bi_private = NULL;
1250 autogroup_def_t **agdp;
1251 autogroup_entry_t *age_next, *age_prev;
1252 autogroup_filter_t *agf,
1255 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1257 for ( i = 0, agdp = &agi->agi_def;
1260 if ( *agdp == NULL) {
1263 agdp = &(*agdp)->agd_next;
1267 *agdp = agd->agd_next;
1269 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1270 age_next = age->age_next;
1272 if( age->age_def == agd ) {
1273 agf = age->age_filter;
1275 ch_free( age->age_dn.bv_val );
1276 ch_free( age->age_ndn.bv_val );
1278 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1279 agf_next = agf->agf_next;
1280 filter_free( agf->agf_filter );
1281 ch_free( agf->agf_filterstr.bv_val );
1282 ch_free( agf->agf_dn.bv_val );
1283 ch_free( agf->agf_ndn.bv_val );
1286 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1291 if( age_prev != NULL ) {
1292 age_prev->age_next = age_next;
1299 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1308 autogroup_def_t **agdp,
1310 ObjectClass *oc = NULL;
1311 AttributeDescription *member_url_ad = NULL,
1316 oc = oc_find( c->argv[ 1 ] );
1318 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1319 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1320 "unable to find ObjectClass \"%s\"",
1322 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1323 c->log, c->cr_msg, 0 );
1328 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1329 if( rc != LDAP_SUCCESS ) {
1330 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1331 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1332 "unable to find AttributeDescription \"%s\"",
1334 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1335 c->log, c->cr_msg, 0 );
1339 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1340 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1341 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1342 "AttributeDescription \"%s\" ",
1343 "must be of a subtype \"labeledURI\"",
1345 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1346 c->log, c->cr_msg, 0 );
1350 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1351 if( rc != LDAP_SUCCESS ) {
1352 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1353 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1354 "unable to find AttributeDescription \"%s\"",
1356 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1357 c->log, c->cr_msg, 0 );
1361 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1363 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1364 /* The same URL attribute / member attribute pair
1365 * cannot be repeated */
1367 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1368 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1369 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1370 "URL attributeDescription \"%s\" already mapped",
1371 member_ad->ad_cname.bv_val );
1372 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1373 c->log, c->cr_msg, 0 );
1374 /* return 1; //warning*/
1378 if ( c->valx > 0 ) {
1381 for ( i = 0, agdp = &agi->agi_def ;
1384 if ( *agdp == NULL ) {
1385 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1386 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1387 "invalid index {%d}",
1389 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1390 c->log, c->cr_msg, 0 );
1392 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1395 agdp = &(*agdp)->agd_next;
1400 for ( agdp = &agi->agi_def; *agdp;
1401 agdp = &(*agdp)->agd_next )
1405 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1407 (*agdp)->agd_oc = oc;
1408 (*agdp)->agd_member_url_ad = member_url_ad;
1409 (*agdp)->agd_member_ad = member_ad;
1410 (*agdp)->agd_next = agd_next;
1412 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1425 ** Do a search for all the groups in the
1426 ** database, and add them to out internal list.
1433 slap_overinst *on = (slap_overinst *) be->bd_info;
1434 autogroup_info_t *agi = on->on_bi.bi_private;
1435 autogroup_def_t *agd;
1438 SlapReply rs = { REP_RESULT };
1439 slap_callback cb = { 0 };
1441 void *thrctx = ldap_pvt_thread_pool_context();
1442 Connection conn = { 0 };
1443 OperationBuffer opbuf;
1445 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1447 connection_fake_init( &conn, &opbuf, thrctx );
1450 op->ors_attrsonly = 0;
1451 op->o_tag = LDAP_REQ_SEARCH;
1452 op->o_dn = be->be_rootdn;
1453 op->o_ndn = be->be_rootndn;
1455 op->o_req_dn = be->be_suffix[0];
1456 op->o_req_ndn = be->be_nsuffix[0];
1458 op->ors_scope = LDAP_SCOPE_SUBTREE;
1459 op->ors_deref = LDAP_DEREF_NEVER;
1460 op->ors_limit = NULL;
1461 op->ors_tlimit = SLAP_NO_LIMIT;
1462 op->ors_slimit = SLAP_NO_LIMIT;
1463 op->ors_attrs = slap_anlist_no_attrs;
1466 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1469 cb.sc_private = &ags;
1470 cb.sc_response = autogroup_group_add_cb;
1471 cb.sc_cleanup = NULL;
1474 op->o_callback = &cb;
1476 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1478 autogroup_build_def_filter(agd, op);
1482 op->o_bd->be_search( op, &rs );
1484 filter_free_x( op, op->ors_filter, 1 );
1485 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1496 slap_overinst *on = (slap_overinst *) be->bd_info;
1498 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1500 if ( on->on_bi.bi_private ) {
1501 autogroup_info_t *agi = on->on_bi.bi_private;
1502 autogroup_entry_t *age = agi->agi_entry,
1504 autogroup_filter_t *agf, *agf_next;
1506 for ( age_next = age; age_next; age = age_next ) {
1507 age_next = age->age_next;
1509 ch_free( age->age_dn.bv_val );
1510 ch_free( age->age_ndn.bv_val );
1512 agf = age->age_filter;
1514 for ( agf_next = agf; agf_next; agf = agf_next ) {
1515 agf_next = agf->agf_next;
1517 filter_free( agf->agf_filter );
1518 ch_free( agf->agf_filterstr.bv_val );
1519 ch_free( agf->agf_dn.bv_val );
1520 ch_free( agf->agf_ndn.bv_val );
1524 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1533 autogroup_db_destroy(
1537 slap_overinst *on = (slap_overinst *) be->bd_info;
1539 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1541 if ( on->on_bi.bi_private ) {
1542 autogroup_info_t *agi = on->on_bi.bi_private;
1543 autogroup_def_t *agd = agi->agi_def,
1546 for ( agd_next = agd; agd_next; agd = agd_next ) {
1547 agd_next = agd->agd_next;
1552 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1559 static slap_overinst autogroup = { { NULL } };
1563 autogroup_initialize(void)
1566 autogroup.on_bi.bi_type = "autogroup";
1568 autogroup.on_bi.bi_db_open = autogroup_db_open;
1569 autogroup.on_bi.bi_db_close = autogroup_db_close;
1570 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1572 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1573 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1574 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1576 autogroup.on_response = autogroup_response;
1578 autogroup.on_bi.bi_cf_ocs = agocs;
1580 rc = config_register_schema( agcfg, agocs );
1585 return overlay_register( &autogroup );
1589 init_module( int argc, char *argv[] )
1591 return autogroup_initialize();