1 /* autogroup.c - automatic group overlay */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2007-2011 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 AttributeName *agf_anlist;
42 struct autogroup_filter_t *agf_next;
45 /* Description of group attributes. */
46 typedef struct autogroup_def_t {
48 AttributeDescription *agd_member_url_ad;
49 AttributeDescription *agd_member_ad;
50 struct autogroup_def_t *agd_next;
53 /* Represents the group entry. */
54 typedef struct autogroup_entry_t {
57 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
58 autogroup_def_t *age_def; /* Attribute definition */
59 ldap_pvt_thread_mutex_t age_mutex;
60 int age_mustrefresh; /* Defined in request to refresh in response */
61 int age_modrdn_olddnmodified; /* Defined in request to refresh in response */
62 struct autogroup_entry_t *age_next;
65 /* Holds pointers to attribute definitions and groups. */
66 typedef struct autogroup_info_t {
67 autogroup_def_t *agi_def; /* Group attributes definitions. */
68 autogroup_entry_t *agi_entry; /* Group entries. */
69 ldap_pvt_thread_mutex_t agi_mutex;
72 /* Search callback for adding groups initially. */
73 typedef struct autogroup_sc_t {
74 autogroup_info_t *ags_info; /* Group definitions and entries. */
75 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
78 /* Used for adding members, found when searching, to a group. */
79 typedef struct autogroup_ga_t {
80 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
81 autogroup_filter_t *agg_filter; /* Current filter */
82 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
83 this entry with the search results. */
85 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
86 search results which will be added to the group. */
88 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
89 have to search for the last mod added. */
94 ** dn, ndn - the DN of the member to add
95 ** age - the group to which the member DN will be added
98 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
100 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
101 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
102 SlapReply sreply = {REP_RESULT};
103 BerValue *vals, *nvals;
104 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
107 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
108 dn->bv_val, age->age_dn.bv_val, 0);
110 assert( dn != NULL );
111 assert( ndn != NULL );
113 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
114 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
115 ber_dupbv( vals, dn );
116 BER_BVZERO( &vals[ 1 ] );
117 ber_dupbv( nvals, ndn );
118 BER_BVZERO( &nvals[ 1 ] );
120 modlist->sml_op = LDAP_MOD_ADD;
121 modlist->sml_desc = age->age_def->agd_member_ad;
122 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
123 modlist->sml_values = vals;
124 modlist->sml_nvalues = nvals;
125 modlist->sml_numvals = 1;
126 modlist->sml_flags = SLAP_MOD_INTERNAL;
127 modlist->sml_next = NULL;
129 o.o_tag = LDAP_REQ_MODIFY;
131 o.orm_modlist = modlist;
132 o.o_req_dn = age->age_dn;
133 o.o_req_ndn = age->age_ndn;
134 o.o_permissive_modify = 1;
135 o.o_managedsait = SLAP_CONTROL_CRITICAL;
136 o.o_relax = SLAP_CONTROL_CRITICAL;
138 o.o_bd->bd_info = (BackendInfo *)on->on_info;
139 (void)op->o_bd->be_modify( &o, &sreply );
140 o.o_bd->bd_info = (BackendInfo *)on;
142 slap_mods_free( modlist, 1 );
144 return sreply.sr_err;
148 ** e - the entry where to get the attribute values
149 ** age - the group to which the values will be added
152 autogroup_add_member_values_to_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc )
154 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
155 Modifications modlist;
156 SlapReply sreply = {REP_RESULT};
158 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
161 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
162 e->e_name.bv_val, age->age_dn.bv_val, 0);
166 attr = attrs_find( e->e_attrs, attrdesc );
172 modlist.sml_op = LDAP_MOD_ADD;
173 modlist.sml_desc = age->age_def->agd_member_ad;
174 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
175 modlist.sml_values = attr->a_vals;
176 modlist.sml_nvalues = attr->a_nvals;
177 modlist.sml_numvals = attr->a_numvals;
178 modlist.sml_flags = SLAP_MOD_INTERNAL;
179 modlist.sml_next = NULL;
181 o.o_tag = LDAP_REQ_MODIFY;
183 o.orm_modlist = &modlist;
184 o.o_req_dn = age->age_dn;
185 o.o_req_ndn = age->age_ndn;
186 o.o_permissive_modify = 1;
187 o.o_managedsait = SLAP_CONTROL_CRITICAL;
188 o.o_relax = SLAP_CONTROL_CRITICAL;
190 o.o_bd->bd_info = (BackendInfo *)on->on_info;
191 (void)op->o_bd->be_modify( &o, &sreply );
192 o.o_bd->bd_info = (BackendInfo *)on;
194 return sreply.sr_err;
198 ** dn,ndn - the DN to be deleted
199 ** age - the group from which the DN will be deleted
200 ** If we pass a NULL dn and ndn, all members are deleted from the group.
203 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
205 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
206 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
207 SlapReply sreply = {REP_RESULT};
208 BerValue *vals, *nvals;
209 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
212 if ( dn == NULL || ndn == NULL ) {
213 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
214 age->age_dn.bv_val, 0 ,0);
216 modlist->sml_values = NULL;
217 modlist->sml_nvalues = NULL;
218 modlist->sml_numvals = 0;
220 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
221 dn->bv_val, age->age_dn.bv_val, 0);
223 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
224 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
225 ber_dupbv( vals, dn );
226 BER_BVZERO( &vals[ 1 ] );
227 ber_dupbv( nvals, ndn );
228 BER_BVZERO( &nvals[ 1 ] );
230 modlist->sml_values = vals;
231 modlist->sml_nvalues = nvals;
232 modlist->sml_numvals = 1;
236 modlist->sml_op = LDAP_MOD_DELETE;
237 modlist->sml_desc = age->age_def->agd_member_ad;
238 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
239 modlist->sml_flags = SLAP_MOD_INTERNAL;
240 modlist->sml_next = NULL;
243 o.o_tag = LDAP_REQ_MODIFY;
244 o.orm_modlist = modlist;
245 o.o_req_dn = age->age_dn;
246 o.o_req_ndn = age->age_ndn;
247 o.o_relax = SLAP_CONTROL_CRITICAL;
248 o.o_managedsait = SLAP_CONTROL_CRITICAL;
249 o.o_permissive_modify = 1;
251 o.o_bd->bd_info = (BackendInfo *)on->on_info;
252 (void)op->o_bd->be_modify( &o, &sreply );
253 o.o_bd->bd_info = (BackendInfo *)on;
255 slap_mods_free( modlist, 1 );
257 return sreply.sr_err;
261 ** Callback used to add entries to a group,
262 ** which are going to be written in the database
263 ** (used in bi_op_add)
264 ** The group is passed in autogroup_ga_t->agg_group
267 autogroup_member_search_cb( Operation *op, SlapReply *rs )
269 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
271 assert( op->o_tag == LDAP_REQ_SEARCH );
273 if ( rs->sr_type == REP_SEARCH ) {
274 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
275 autogroup_entry_t *age = agg->agg_group;
276 autogroup_filter_t *agf = agg->agg_filter;
278 const char *text = NULL;
280 struct berval *vals, *nvals;
283 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
284 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
286 if ( agf->agf_anlist ) {
287 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
290 nvals = attr->a_nvals;
291 numvals = attr->a_numvals;
297 struct berval lvals[ 2 ], lnvals[ 2 ];
298 lvals[ 0 ] = rs->sr_entry->e_name;
299 BER_BVZERO( &lvals[ 1 ] );
300 lnvals[ 0 ] = rs->sr_entry->e_nname;
301 BER_BVZERO( &lnvals[ 1 ] );
307 mod.sm_op = LDAP_MOD_ADD;
308 mod.sm_desc = age->age_def->agd_member_ad;
309 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
310 mod.sm_values = vals;
311 mod.sm_nvalues = nvals;
312 mod.sm_numvals = numvals;
314 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
321 ** Callback used to add entries to a group, which is already in the database.
322 ** (used in on_response)
323 ** The group is passed in autogroup_ga_t->agg_group
327 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
329 assert( op->o_tag == LDAP_REQ_SEARCH );
331 if ( rs->sr_type == REP_SEARCH ) {
332 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
333 autogroup_entry_t *age = agg->agg_group;
334 autogroup_filter_t *agf = agg->agg_filter;
335 Modifications *modlist;
336 struct berval *vals, *nvals;
339 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
340 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
342 if ( agf->agf_anlist ) {
343 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
346 nvals = attr->a_nvals;
347 numvals = attr->a_numvals;
353 struct berval lvals[ 2 ], lnvals[ 2 ];
354 lvals[ 0 ] = rs->sr_entry->e_name;
355 BER_BVZERO( &lvals[ 1 ] );
356 lnvals[ 0 ] = rs->sr_entry->e_nname;
357 BER_BVZERO( &lnvals[ 1 ] );
364 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
366 modlist->sml_op = LDAP_MOD_ADD;
367 modlist->sml_desc = age->age_def->agd_member_ad;
368 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
370 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
371 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
372 modlist->sml_numvals = numvals;
374 modlist->sml_flags = SLAP_MOD_INTERNAL;
375 modlist->sml_next = NULL;
377 if ( agg->agg_mod == NULL ) {
378 agg->agg_mod = modlist;
379 agg->agg_mod_last = modlist;
381 agg->agg_mod_last->sml_next = modlist;
382 agg->agg_mod_last = modlist;
393 ** Adds all entries matching the passed filter to the specified group.
394 ** If modify == 1, then we modify the group's entry in the database using be_modify.
395 ** If modify == 0, then, we must supply a rw entry for the group,
396 ** because we only modify the entry, without calling be_modify.
397 ** e - the group entry, to which the members will be added
402 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
404 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
406 SlapReply rs = { REP_SEARCH };
407 slap_callback cb = { 0 };
408 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
411 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
412 age->age_dn.bv_val, 0, 0);
415 o.o_tag = LDAP_REQ_SEARCH;
417 o.o_req_dn = agf->agf_dn;
418 o.o_req_ndn = agf->agf_ndn;
420 o.ors_filterstr = agf->agf_filterstr;
421 o.ors_filter = agf->agf_filter;
423 o.ors_scope = agf->agf_scope;
424 o.ors_deref = LDAP_DEREF_NEVER;
426 o.ors_tlimit = SLAP_NO_LIMIT;
427 o.ors_slimit = SLAP_NO_LIMIT;
428 o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
431 agg.agg_filter = agf;
433 agg.agg_mod_last = NULL;
435 cb.sc_private = &agg;
438 cb.sc_response = autogroup_member_search_modify_cb;
440 cb.sc_response = autogroup_member_search_cb;
443 cb.sc_cleanup = NULL;
448 o.o_bd->bd_info = (BackendInfo *)on->on_info;
449 op->o_bd->be_search( &o, &rs );
450 o.o_bd->bd_info = (BackendInfo *)on;
452 if ( modify == 1 && agg.agg_mod ) {
453 rs_reinit( &rs, REP_RESULT );
456 o.o_callback = &null_cb;
457 o.o_tag = LDAP_REQ_MODIFY;
458 o.orm_modlist = agg.agg_mod;
459 o.o_req_dn = age->age_dn;
460 o.o_req_ndn = age->age_ndn;
461 o.o_relax = SLAP_CONTROL_CRITICAL;
462 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
463 o.o_permissive_modify = 1;
465 o.o_bd->bd_info = (BackendInfo *)on->on_info;
466 (void)op->o_bd->be_modify( &o, &rs );
467 o.o_bd->bd_info = (BackendInfo *)on;
469 slap_mods_free(agg.agg_mod, 1);
476 ** Adds a group to the internal list from the passed entry.
477 ** scan specifies whether to add all maching members to the group.
478 ** modify specifies whether to modify the given group entry (when modify == 0),
479 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
480 ** agi - pointer to the groups and the attribute definitions
481 ** agd - the attribute definition of the added group
482 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
483 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
486 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
488 autogroup_entry_t **agep = &agi->agi_entry;
489 autogroup_filter_t *agf, *agf_prev = NULL;
490 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
491 LDAPURLDesc *lud = NULL;
494 int rc = 0, match = 1, null_entry = 0;
497 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
498 LDAP_SUCCESS || e == NULL ) {
499 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
506 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
507 e->e_name.bv_val, 0, 0);
509 if ( agi->agi_entry != NULL ) {
510 for ( ; *agep ; agep = &(*agep)->age_next ) {
511 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
513 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
521 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
522 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
523 (*agep)->age_def = agd;
524 (*agep)->age_filter = NULL;
525 (*agep)->age_mustrefresh = 0;
526 (*agep)->age_modrdn_olddnmodified = 0;
528 ber_dupbv( &(*agep)->age_dn, &e->e_name );
529 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
531 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
533 if ( null_entry == 1 ) {
535 overlay_entry_release_ov( op, e, 0, on );
539 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
541 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
543 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
545 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
546 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
552 agf->agf_scope = lud->lud_scope;
554 if ( lud->lud_dn == NULL ) {
555 BER_BVSTR( &dn, "" );
557 ber_str2bv( lud->lud_dn, 0, 0, &dn );
560 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
561 if ( rc != LDAP_SUCCESS ) {
562 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
567 if ( lud->lud_filter != NULL ) {
568 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
569 agf->agf_filter = str2filter( lud->lud_filter );
572 if ( lud->lud_attrs != NULL ) {
575 for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
580 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: to much attributes specified in url <%s>\n",
583 ldap_free_urldesc( lud );
587 agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
589 if ( agf->agf_anlist == NULL ) {
590 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
591 lud->lud_attrs[0], 0, 0 );
593 ldap_free_urldesc( lud );
599 agf->agf_next = NULL;
602 if( (*agep)->age_filter == NULL ) {
603 (*agep)->age_filter = agf;
606 if( agf_prev != NULL ) {
607 agf_prev->agf_next = agf;
613 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
616 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
617 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
619 ldap_free_urldesc( lud );
626 ldap_free_urldesc( lud );
631 if ( null_entry == 1 ) {
638 ** Used when opening the database to add all existing
639 ** groups from the database to our internal list.
642 autogroup_group_add_cb( Operation *op, SlapReply *rs )
644 assert( op->o_tag == LDAP_REQ_SEARCH );
646 if ( rs->sr_type == REP_SEARCH ) {
647 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
649 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
650 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
652 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
660 ** When adding a group, we first strip any existing members,
661 ** and add all which match the filters ourselfs.
664 autogroup_add_entry( Operation *op, SlapReply *rs)
666 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
667 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
668 autogroup_def_t *agd = agi->agi_def;
669 autogroup_entry_t *age = agi->agi_entry;
670 autogroup_filter_t *agf;
673 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
674 op->ora_e->e_name.bv_val, 0, 0);
676 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
678 /* Check if it's a group. */
679 for ( ; agd ; agd = agd->agd_next ) {
680 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
682 const char *text = NULL;
685 mod.sm_op = LDAP_MOD_DELETE;
686 mod.sm_desc = agd->agd_member_ad;
687 mod.sm_type = agd->agd_member_ad->ad_cname;
688 mod.sm_values = NULL;
689 mod.sm_nvalues = NULL;
691 /* We don't want any member attributes added by the user. */
692 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
694 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
695 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
696 return SLAP_CB_CONTINUE;
700 for ( ; age ; age = age->age_next ) {
701 ldap_pvt_thread_mutex_lock( &age->age_mutex );
703 /* Check if any of the filters are the suffix to the entry DN.
704 If yes, we can test that filter against the entry. */
706 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
707 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
708 rc = test_filter( op, op->ora_e, agf->agf_filter );
709 if ( rc == LDAP_COMPARE_TRUE ) {
710 if ( agf->agf_anlist ) {
711 autogroup_add_member_values_to_group( op, op->ora_e, age, agf->agf_anlist[0].an_desc );
713 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
719 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
722 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
724 return SLAP_CB_CONTINUE;
728 ** agi - internal group and attribute definitions list
729 ** e - the group to remove from the internal list
732 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
734 autogroup_entry_t *age = agi->agi_entry,
739 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
740 age->age_dn.bv_val, 0, 0);
742 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
743 age_next = age->age_next;
746 autogroup_filter_t *agf = age->age_filter,
749 if ( age_prev != NULL ) {
750 age_prev->age_next = age_next;
752 agi->agi_entry = NULL;
755 ch_free( age->age_dn.bv_val );
756 ch_free( age->age_ndn.bv_val );
758 for( agf_next = agf ; agf_next ; agf = agf_next ){
759 agf_next = agf->agf_next;
761 filter_free( agf->agf_filter );
762 ch_free( agf->agf_filterstr.bv_val );
763 ch_free( agf->agf_dn.bv_val );
764 ch_free( agf->agf_ndn.bv_val );
765 anlist_free( agf->agf_anlist, 1, NULL );
769 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
770 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
779 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
786 autogroup_delete_entry( Operation *op, SlapReply *rs)
788 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
789 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
790 autogroup_entry_t *age = agi->agi_entry,
791 *age_prev, *age_next;
792 autogroup_filter_t *agf;
794 int matched_group = 0, rc = 0;
796 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
798 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
800 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
801 LDAP_SUCCESS || e == NULL ) {
802 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
803 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
804 return SLAP_CB_CONTINUE;
807 /* Check if the entry to be deleted is one of our groups. */
808 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
809 ldap_pvt_thread_mutex_lock( &age->age_mutex );
810 age_next = age->age_next;
812 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
817 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
820 autogroup_delete_group( agi, age );
825 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
828 if ( matched_group == 1 ) {
829 overlay_entry_release_ov( op, e, 0, on );
830 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
831 return SLAP_CB_CONTINUE;
834 /* Check if the entry matches any of the groups.
835 If yes, we can delete the entry from that group. */
837 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
838 ldap_pvt_thread_mutex_lock( &age->age_mutex );
840 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
841 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
842 rc = test_filter( op, e, agf->agf_filter );
843 if ( rc == LDAP_COMPARE_TRUE ) {
844 /* If the attribute is retrieved from the entry, we don't know what to delete
845 ** So the group must be entirely refreshed
846 ** But the refresh can't be done now because the entry is not deleted
847 ** So the group is marked as mustrefresh
849 if ( agf->agf_anlist ) {
850 age->age_mustrefresh = 1;
852 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
858 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
861 overlay_entry_release_ov( op, e, 0, on );
862 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
864 return SLAP_CB_CONTINUE;
868 autogroup_response( Operation *op, SlapReply *rs )
870 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
871 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
872 autogroup_def_t *agd = agi->agi_def;
873 autogroup_entry_t *age = agi->agi_entry;
874 autogroup_filter_t *agf;
875 BerValue new_dn, new_ndn, pdn;
878 int is_olddn, is_newdn, is_value_refresh, dn_equal;
880 /* Handle all cases where a refresh of the group is needed */
881 if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
882 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
884 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
886 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
887 /* Request detected that the group must be refreshed */
889 ldap_pvt_thread_mutex_lock( &age->age_mutex );
891 if ( age->age_mustrefresh ) {
892 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
894 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
895 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
899 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
902 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
905 if ( op->o_tag == LDAP_REQ_MODRDN ) {
906 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
908 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
910 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
912 if ( op->oq_modrdn.rs_newSup ) {
913 pdn = *op->oq_modrdn.rs_newSup;
915 dnParent( &op->o_req_dn, &pdn );
917 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
919 if ( op->oq_modrdn.rs_nnewSup ) {
920 pdn = *op->oq_modrdn.rs_nnewSup;
922 dnParent( &op->o_req_ndn, &pdn );
924 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
926 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
928 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
930 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
931 LDAP_SUCCESS || e == NULL ) {
932 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
933 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
934 return SLAP_CB_CONTINUE;
937 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
941 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
942 overlay_entry_release_ov( op, e, 0, on );
943 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
944 return SLAP_CB_CONTINUE;
948 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
949 for ( ; agd; agd = agd->agd_next ) {
951 if ( value_find_ex( slap_schema.si_ad_objectClass,
952 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
953 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
954 a->a_nvals, &agd->agd_oc->soc_cname,
955 op->o_tmpmemctx ) == 0 )
957 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
960 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
962 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
963 ber_dupbv( &age->age_dn, &new_dn );
964 ber_dupbv( &age->age_ndn, &new_ndn );
966 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
967 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
968 overlay_entry_release_ov( op, e, 0, on );
969 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
970 return SLAP_CB_CONTINUE;
977 overlay_entry_release_ov( op, e, 0, on );
980 1. check if the orginal entry's DN is in the group.
981 2. chceck if the any of the group filter's base DN is a suffix of the new DN
983 If 1 and 2 are both false, we do nothing.
984 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
985 If 1 is false, and 2 is true, we check the entry against the group's filters,
986 and add it's DN to the group.
987 If 1 is true, and 2 is false, we delete the entry's DN from the group.
989 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
992 is_value_refresh = 0;
995 ldap_pvt_thread_mutex_lock( &age->age_mutex );
997 if ( age->age_modrdn_olddnmodified ) {
998 /* Resquest already marked this group to be updated */
1000 is_value_refresh = 1;
1001 age->age_modrdn_olddnmodified = 0;
1004 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1005 LDAP_SUCCESS || group == NULL ) {
1006 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
1008 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1009 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1011 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1012 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1013 return SLAP_CB_CONTINUE;
1016 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1019 if ( value_find_ex( age->age_def->agd_member_ad,
1020 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1021 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1022 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1029 overlay_entry_release_ov( op, group, 0, on );
1033 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1034 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
1035 /* TODO: should retest filter as it could imply conditions on the dn */
1042 if ( is_value_refresh ) {
1043 if ( is_olddn != is_newdn ) {
1045 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1047 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1048 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1051 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1054 if ( is_olddn == 1 && is_newdn == 0 ) {
1055 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1057 if ( is_olddn == 0 && is_newdn == 1 ) {
1058 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
1059 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1060 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1065 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
1066 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1067 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1070 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1073 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1074 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1076 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1080 if ( op->o_tag == LDAP_REQ_MODIFY ) {
1081 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
1082 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
1084 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1086 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1087 LDAP_SUCCESS || e == NULL ) {
1088 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1089 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1090 return SLAP_CB_CONTINUE;
1093 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1097 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1098 overlay_entry_release_ov( op, e, 0, on );
1099 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1100 return SLAP_CB_CONTINUE;
1104 /* If we modify a group's memberURL, we have to delete all of it's members,
1105 and add them anew, because we cannot tell from which memberURL a member was added. */
1106 for ( ; agd; agd = agd->agd_next ) {
1108 if ( value_find_ex( slap_schema.si_ad_objectClass,
1109 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1110 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1111 a->a_nvals, &agd->agd_oc->soc_cname,
1112 op->o_tmpmemctx ) == 0 )
1117 m = op->orm_modlist;
1119 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1120 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1122 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1125 for ( ; m ; m = m->sml_next ) {
1126 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
1127 autogroup_def_t *group_agd = age->age_def;
1128 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
1129 op->o_req_dn.bv_val, 0, 0);
1131 overlay_entry_release_ov( op, e, 0, on );
1133 autogroup_delete_member_from_group( op, NULL, NULL, age );
1134 autogroup_delete_group( agi, age );
1136 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
1138 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1139 return SLAP_CB_CONTINUE;
1143 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1147 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1150 overlay_entry_release_ov( op, e, 0, on );
1151 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1152 return SLAP_CB_CONTINUE;
1156 overlay_entry_release_ov( op, e, 0, on );
1158 /* When modifing any of the attributes of an entry, we must
1159 check if the entry is in any of our groups, and if
1160 the modified entry maches any of the filters of that group.
1162 If the entry exists in a group, but the modified attributes do
1163 not match any of the group's filters, we delete the entry from that group.
1164 If the entry doesn't exist in a group, but matches a filter,
1165 we add it to that group.
1167 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1172 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1174 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1175 LDAP_SUCCESS || group == NULL ) {
1176 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
1177 age->age_dn.bv_val, 0, 0);
1179 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1180 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1181 return SLAP_CB_CONTINUE;
1184 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1187 if ( value_find_ex( age->age_def->agd_member_ad,
1188 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1189 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1190 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1197 overlay_entry_release_ov( op, group, 0, on );
1199 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1200 if ( !agf->agf_anlist && dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1201 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1208 if ( is_olddn == 1 && is_newdn == 0 ) {
1209 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1211 if ( is_olddn == 0 && is_newdn == 1 ) {
1212 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1215 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1218 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1222 return SLAP_CB_CONTINUE;
1226 ** When modifing a group, we must deny any modifications to the member attribute,
1227 ** because the group would be inconsistent.
1230 autogroup_modify_entry( Operation *op, SlapReply *rs)
1232 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1233 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1234 autogroup_def_t *agd = agi->agi_def;
1235 autogroup_entry_t *age = agi->agi_entry;
1239 if ( get_manageDSAit( op ) ) {
1240 return SLAP_CB_CONTINUE;
1243 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1244 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1246 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1247 LDAP_SUCCESS || e == NULL ) {
1248 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1249 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1250 return SLAP_CB_CONTINUE;
1253 /* Must refresh groups if a matching member value is modified */
1254 for ( ; age ; age = age->age_next ) {
1255 autogroup_filter_t *agf;
1256 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1257 if ( agf->agf_anlist ) {
1259 for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
1260 if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
1261 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1262 int rc = test_filter( op, e, agf->agf_filter );
1263 if ( rc == LDAP_COMPARE_TRUE ) {
1264 age->age_mustrefresh = 1;
1273 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1276 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1277 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1278 return SLAP_CB_CONTINUE;
1282 for ( ; agd; agd = agd->agd_next ) {
1284 if ( value_find_ex( slap_schema.si_ad_objectClass,
1285 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1286 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1287 a->a_nvals, &agd->agd_oc->soc_cname,
1288 op->o_tmpmemctx ) == 0 )
1293 m = op->orm_modlist;
1295 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1296 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1299 for ( ; m ; m = m->sml_next ) {
1300 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1301 overlay_entry_release_ov( op, e, 0, on );
1302 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1303 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1304 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1305 return LDAP_CONSTRAINT_VIOLATION;
1312 overlay_entry_release_ov( op, e, 0, on );
1313 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1314 return SLAP_CB_CONTINUE;
1318 overlay_entry_release_ov( op, e, 0, on );
1319 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1320 return SLAP_CB_CONTINUE;
1324 ** Detect if the olddn is part of a group and so if the group should be refreshed
1327 autogroup_modrdn_entry( Operation *op, SlapReply *rs)
1329 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1330 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1331 autogroup_entry_t *age = agi->agi_entry;
1334 if ( get_manageDSAit( op ) ) {
1335 return SLAP_CB_CONTINUE;
1338 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1339 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1341 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1342 LDAP_SUCCESS || e == NULL ) {
1343 Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1344 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1345 return SLAP_CB_CONTINUE;
1348 /* Must check if a dn is modified */
1349 for ( ; age ; age = age->age_next ) {
1350 autogroup_filter_t *agf;
1351 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1352 if ( agf->agf_anlist ) {
1353 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1354 int rc = test_filter( op, e, agf->agf_filter );
1355 if ( rc == LDAP_COMPARE_TRUE ) {
1356 age->age_modrdn_olddnmodified = 1;
1363 overlay_entry_release_ov( op, e, 0, on );
1364 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1365 return SLAP_CB_CONTINUE;
1369 ** Builds a filter for searching for the
1370 ** group entries, according to the objectClass.
1373 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1377 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1379 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1380 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1381 + agd->agd_oc->soc_cname.bv_len;
1382 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1384 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1386 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1390 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1392 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1402 static ConfigDriver ag_cfgen;
1404 static ConfigTable agcfg[] = {
1405 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1406 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1407 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1408 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1409 "EQUALITY caseIgnoreMatch "
1410 "SYNTAX OMsDirectoryString "
1411 "X-ORDERED 'VALUES' )",
1413 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1416 static ConfigOCs agocs[] = {
1417 { "( OLcfgCtOc:2.1 "
1418 "NAME 'olcAutomaticGroups' "
1419 "DESC 'Automatic groups configuration' "
1420 "SUP olcOverlayConfig "
1421 "MAY olcAGattrSet )",
1422 Cft_Overlay, agcfg, NULL, NULL },
1428 ag_cfgen( ConfigArgs *c )
1430 slap_overinst *on = (slap_overinst *)c->bi;
1431 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1432 autogroup_def_t *agd;
1433 autogroup_entry_t *age;
1437 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1440 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1441 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1442 agi->agi_def = NULL;
1443 agi->agi_entry = NULL;
1444 on->on_bi.bi_private = (void *)agi;
1448 age = agi->agi_entry;
1450 if ( c->op == SLAP_CONFIG_EMIT ) {
1452 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1454 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1456 char *ptr = c->cr_msg;
1458 assert(agd->agd_oc != NULL);
1459 assert(agd->agd_member_url_ad != NULL);
1460 assert(agd->agd_member_ad != NULL);
1462 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1463 SLAP_X_ORDERED_FMT "%s %s %s", i,
1464 agd->agd_oc->soc_cname.bv_val,
1465 agd->agd_member_url_ad->ad_cname.bv_val,
1466 agd->agd_member_ad->ad_cname.bv_val );
1468 bv.bv_val = c->cr_msg;
1469 bv.bv_len = ptr - bv.bv_val;
1470 value_add_one ( &c->rvalue_vals, &bv );
1473 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1477 }else if ( c->op == LDAP_MOD_DELETE ) {
1479 autogroup_def_t *agd_next;
1480 autogroup_entry_t *age_next;
1481 autogroup_filter_t *agf = age->age_filter,
1484 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1486 for ( agd_next = agd; agd_next; agd = agd_next ) {
1487 agd_next = agd->agd_next;
1492 for ( age_next = age ; age_next ; age = age_next ) {
1493 age_next = age->age_next;
1495 ch_free( age->age_dn.bv_val );
1496 ch_free( age->age_ndn.bv_val );
1498 for( agf_next = agf ; agf_next ; agf = agf_next ){
1499 agf_next = agf->agf_next;
1501 filter_free( agf->agf_filter );
1502 ch_free( agf->agf_filterstr.bv_val );
1503 ch_free( agf->agf_dn.bv_val );
1504 ch_free( agf->agf_ndn.bv_val );
1505 anlist_free( agf->agf_anlist, 1, NULL );
1509 ldap_pvt_thread_mutex_init( &age->age_mutex );
1513 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1515 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1517 on->on_bi.bi_private = NULL;
1520 autogroup_def_t **agdp;
1521 autogroup_entry_t *age_next, *age_prev;
1522 autogroup_filter_t *agf,
1525 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1527 for ( i = 0, agdp = &agi->agi_def;
1530 if ( *agdp == NULL) {
1533 agdp = &(*agdp)->agd_next;
1537 *agdp = agd->agd_next;
1539 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1540 age_next = age->age_next;
1542 if( age->age_def == agd ) {
1543 agf = age->age_filter;
1545 ch_free( age->age_dn.bv_val );
1546 ch_free( age->age_ndn.bv_val );
1548 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1549 agf_next = agf->agf_next;
1550 filter_free( agf->agf_filter );
1551 ch_free( agf->agf_filterstr.bv_val );
1552 ch_free( agf->agf_dn.bv_val );
1553 ch_free( agf->agf_ndn.bv_val );
1554 anlist_free( agf->agf_anlist, 1, NULL );
1558 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1563 if( age_prev != NULL ) {
1564 age_prev->age_next = age_next;
1571 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1580 autogroup_def_t **agdp,
1582 ObjectClass *oc = NULL;
1583 AttributeDescription *member_url_ad = NULL,
1588 oc = oc_find( c->argv[ 1 ] );
1590 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1591 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1592 "unable to find ObjectClass \"%s\"",
1594 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1595 c->log, c->cr_msg, 0 );
1600 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1601 if( rc != LDAP_SUCCESS ) {
1602 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1603 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1604 "unable to find AttributeDescription \"%s\"",
1606 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1607 c->log, c->cr_msg, 0 );
1611 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1612 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1613 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1614 "AttributeDescription \"%s\" ",
1615 "must be of a subtype \"labeledURI\"",
1617 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1618 c->log, c->cr_msg, 0 );
1622 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1623 if( rc != LDAP_SUCCESS ) {
1624 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1625 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1626 "unable to find AttributeDescription \"%s\"",
1628 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1629 c->log, c->cr_msg, 0 );
1633 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1635 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1636 /* The same URL attribute / member attribute pair
1637 * cannot be repeated */
1639 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1640 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1641 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1642 "URL attributeDescription \"%s\" already mapped",
1643 member_ad->ad_cname.bv_val );
1644 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1645 c->log, c->cr_msg, 0 );
1646 /* return 1; //warning*/
1650 if ( c->valx > 0 ) {
1653 for ( i = 0, agdp = &agi->agi_def ;
1656 if ( *agdp == NULL ) {
1657 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1658 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1659 "invalid index {%d}",
1661 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1662 c->log, c->cr_msg, 0 );
1664 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1667 agdp = &(*agdp)->agd_next;
1672 for ( agdp = &agi->agi_def; *agdp;
1673 agdp = &(*agdp)->agd_next )
1677 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1679 (*agdp)->agd_oc = oc;
1680 (*agdp)->agd_member_url_ad = member_url_ad;
1681 (*agdp)->agd_member_ad = member_ad;
1682 (*agdp)->agd_next = agd_next;
1684 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1697 ** Do a search for all the groups in the
1698 ** database, and add them to out internal list.
1705 slap_overinst *on = (slap_overinst *) be->bd_info;
1706 autogroup_info_t *agi = on->on_bi.bi_private;
1707 autogroup_def_t *agd;
1710 slap_callback cb = { 0 };
1712 void *thrctx = ldap_pvt_thread_pool_context();
1713 Connection conn = { 0 };
1714 OperationBuffer opbuf;
1716 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1718 if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
1722 connection_fake_init( &conn, &opbuf, thrctx );
1725 op->ors_attrsonly = 0;
1726 op->o_tag = LDAP_REQ_SEARCH;
1727 op->o_dn = be->be_rootdn;
1728 op->o_ndn = be->be_rootndn;
1730 op->o_req_dn = be->be_suffix[0];
1731 op->o_req_ndn = be->be_nsuffix[0];
1733 op->ors_scope = LDAP_SCOPE_SUBTREE;
1734 op->ors_deref = LDAP_DEREF_NEVER;
1735 op->ors_limit = NULL;
1736 op->ors_tlimit = SLAP_NO_LIMIT;
1737 op->ors_slimit = SLAP_NO_LIMIT;
1738 op->ors_attrs = slap_anlist_no_attrs;
1741 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1744 cb.sc_private = &ags;
1745 cb.sc_response = autogroup_group_add_cb;
1746 cb.sc_cleanup = NULL;
1749 op->o_callback = &cb;
1751 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1752 SlapReply rs = { REP_RESULT };
1754 autogroup_build_def_filter(agd, op);
1758 op->o_bd->be_search( op, &rs );
1760 filter_free_x( op, op->ors_filter, 1 );
1761 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1772 slap_overinst *on = (slap_overinst *) be->bd_info;
1774 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1776 if ( on->on_bi.bi_private ) {
1777 autogroup_info_t *agi = on->on_bi.bi_private;
1778 autogroup_entry_t *age = agi->agi_entry,
1780 autogroup_filter_t *agf, *agf_next;
1782 for ( age_next = age; age_next; age = age_next ) {
1783 age_next = age->age_next;
1785 ch_free( age->age_dn.bv_val );
1786 ch_free( age->age_ndn.bv_val );
1788 agf = age->age_filter;
1790 for ( agf_next = agf; agf_next; agf = agf_next ) {
1791 agf_next = agf->agf_next;
1793 filter_free( agf->agf_filter );
1794 ch_free( agf->agf_filterstr.bv_val );
1795 ch_free( agf->agf_dn.bv_val );
1796 ch_free( agf->agf_ndn.bv_val );
1797 anlist_free( agf->agf_anlist, 1, NULL );
1801 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1810 autogroup_db_destroy(
1814 slap_overinst *on = (slap_overinst *) be->bd_info;
1816 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1818 if ( on->on_bi.bi_private ) {
1819 autogroup_info_t *agi = on->on_bi.bi_private;
1820 autogroup_def_t *agd = agi->agi_def,
1823 for ( agd_next = agd; agd_next; agd = agd_next ) {
1824 agd_next = agd->agd_next;
1829 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1836 static slap_overinst autogroup = { { NULL } };
1840 autogroup_initialize(void)
1843 autogroup.on_bi.bi_type = "autogroup";
1845 autogroup.on_bi.bi_db_open = autogroup_db_open;
1846 autogroup.on_bi.bi_db_close = autogroup_db_close;
1847 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1849 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1850 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1851 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1852 autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
1854 autogroup.on_response = autogroup_response;
1856 autogroup.on_bi.bi_cf_ocs = agocs;
1858 rc = config_register_schema( agcfg, agocs );
1863 return overlay_register( &autogroup );
1867 init_module( int argc, char *argv[] )
1869 return autogroup_initialize();