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 ) {
454 o.o_callback = &null_cb;
455 o.o_tag = LDAP_REQ_MODIFY;
456 o.orm_modlist = agg.agg_mod;
457 o.o_req_dn = age->age_dn;
458 o.o_req_ndn = age->age_ndn;
459 o.o_relax = SLAP_CONTROL_CRITICAL;
460 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
461 o.o_permissive_modify = 1;
463 o.o_bd->bd_info = (BackendInfo *)on->on_info;
464 (void)op->o_bd->be_modify( &o, &rs );
465 o.o_bd->bd_info = (BackendInfo *)on;
467 slap_mods_free(agg.agg_mod, 1);
474 ** Adds a group to the internal list from the passed entry.
475 ** scan specifies whether to add all maching members to the group.
476 ** modify specifies whether to modify the given group entry (when modify == 0),
477 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
478 ** agi - pointer to the groups and the attribute definitions
479 ** agd - the attribute definition of the added group
480 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
481 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
484 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
486 autogroup_entry_t **agep = &agi->agi_entry;
487 autogroup_filter_t *agf, *agf_prev = NULL;
488 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
489 LDAPURLDesc *lud = NULL;
492 int rc = 0, match = 1, null_entry = 0;
495 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
496 LDAP_SUCCESS || e == NULL ) {
497 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
504 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
505 e->e_name.bv_val, 0, 0);
507 if ( agi->agi_entry != NULL ) {
508 for ( ; *agep ; agep = &(*agep)->age_next ) {
509 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
511 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
519 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
520 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
521 (*agep)->age_def = agd;
522 (*agep)->age_filter = NULL;
523 (*agep)->age_mustrefresh = 0;
524 (*agep)->age_modrdn_olddnmodified = 0;
526 ber_dupbv( &(*agep)->age_dn, &e->e_name );
527 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
529 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
531 if ( null_entry == 1 ) {
533 overlay_entry_release_ov( op, e, 0, on );
537 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
539 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
541 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
543 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
544 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
550 agf->agf_scope = lud->lud_scope;
552 if ( lud->lud_dn == NULL ) {
553 BER_BVSTR( &dn, "" );
555 ber_str2bv( lud->lud_dn, 0, 0, &dn );
558 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
559 if ( rc != LDAP_SUCCESS ) {
560 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
565 if ( lud->lud_filter != NULL ) {
566 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
567 agf->agf_filter = str2filter( lud->lud_filter );
570 if ( lud->lud_attrs != NULL ) {
573 for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
578 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: to much attributes specified in url <%s>\n",
581 ldap_free_urldesc( lud );
585 agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
587 if ( agf->agf_anlist == NULL ) {
588 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
589 lud->lud_attrs[0], 0, 0 );
591 ldap_free_urldesc( lud );
597 agf->agf_next = NULL;
600 if( (*agep)->age_filter == NULL ) {
601 (*agep)->age_filter = agf;
604 if( agf_prev != NULL ) {
605 agf_prev->agf_next = agf;
611 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
614 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
615 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
617 ldap_free_urldesc( lud );
624 ldap_free_urldesc( lud );
629 if ( null_entry == 1 ) {
636 ** Used when opening the database to add all existing
637 ** groups from the database to our internal list.
640 autogroup_group_add_cb( Operation *op, SlapReply *rs )
642 assert( op->o_tag == LDAP_REQ_SEARCH );
644 if ( rs->sr_type == REP_SEARCH ) {
645 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
647 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
648 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
650 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
658 ** When adding a group, we first strip any existing members,
659 ** and add all which match the filters ourselfs.
662 autogroup_add_entry( Operation *op, SlapReply *rs)
664 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
665 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
666 autogroup_def_t *agd = agi->agi_def;
667 autogroup_entry_t *age = agi->agi_entry;
668 autogroup_filter_t *agf;
671 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
672 op->ora_e->e_name.bv_val, 0, 0);
674 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
676 /* Check if it's a group. */
677 for ( ; agd ; agd = agd->agd_next ) {
678 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
680 const char *text = NULL;
683 mod.sm_op = LDAP_MOD_DELETE;
684 mod.sm_desc = agd->agd_member_ad;
685 mod.sm_type = agd->agd_member_ad->ad_cname;
686 mod.sm_values = NULL;
687 mod.sm_nvalues = NULL;
689 /* We don't want any member attributes added by the user. */
690 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
692 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
693 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
694 return SLAP_CB_CONTINUE;
698 for ( ; age ; age = age->age_next ) {
699 ldap_pvt_thread_mutex_lock( &age->age_mutex );
701 /* Check if any of the filters are the suffix to the entry DN.
702 If yes, we can test that filter against the entry. */
704 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
705 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
706 rc = test_filter( op, op->ora_e, agf->agf_filter );
707 if ( rc == LDAP_COMPARE_TRUE ) {
708 if ( agf->agf_anlist ) {
709 autogroup_add_member_values_to_group( op, op->ora_e, age, agf->agf_anlist[0].an_desc );
711 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
717 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
720 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
722 return SLAP_CB_CONTINUE;
726 ** agi - internal group and attribute definitions list
727 ** e - the group to remove from the internal list
730 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
732 autogroup_entry_t *age = agi->agi_entry,
737 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
738 age->age_dn.bv_val, 0, 0);
740 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
741 age_next = age->age_next;
744 autogroup_filter_t *agf = age->age_filter,
747 if ( age_prev != NULL ) {
748 age_prev->age_next = age_next;
750 agi->agi_entry = NULL;
753 ch_free( age->age_dn.bv_val );
754 ch_free( age->age_ndn.bv_val );
756 for( agf_next = agf ; agf_next ; agf = agf_next ){
757 agf_next = agf->agf_next;
759 filter_free( agf->agf_filter );
760 ch_free( agf->agf_filterstr.bv_val );
761 ch_free( agf->agf_dn.bv_val );
762 ch_free( agf->agf_ndn.bv_val );
763 anlist_free( agf->agf_anlist, 1, NULL );
767 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
768 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
777 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
784 autogroup_delete_entry( Operation *op, SlapReply *rs)
786 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
787 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
788 autogroup_entry_t *age = agi->agi_entry,
789 *age_prev, *age_next;
790 autogroup_filter_t *agf;
792 int matched_group = 0, rc = 0;
794 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
796 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
798 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
799 LDAP_SUCCESS || e == NULL ) {
800 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
801 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
802 return SLAP_CB_CONTINUE;
805 /* Check if the entry to be deleted is one of our groups. */
806 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
807 ldap_pvt_thread_mutex_lock( &age->age_mutex );
808 age_next = age->age_next;
810 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
815 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
818 autogroup_delete_group( agi, age );
823 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
826 if ( matched_group == 1 ) {
827 overlay_entry_release_ov( op, e, 0, on );
828 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
829 return SLAP_CB_CONTINUE;
832 /* Check if the entry matches any of the groups.
833 If yes, we can delete the entry from that group. */
835 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
836 ldap_pvt_thread_mutex_lock( &age->age_mutex );
838 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
839 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
840 rc = test_filter( op, e, agf->agf_filter );
841 if ( rc == LDAP_COMPARE_TRUE ) {
842 /* If the attribute is retrieved from the entry, we don't know what to delete
843 ** So the group must be entirely refreshed
844 ** But the refresh can't be done now because the entry is not deleted
845 ** So the group is marked as mustrefresh
847 if ( agf->agf_anlist ) {
848 age->age_mustrefresh = 1;
850 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
856 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
859 overlay_entry_release_ov( op, e, 0, on );
860 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
862 return SLAP_CB_CONTINUE;
866 autogroup_response( Operation *op, SlapReply *rs )
868 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
869 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
870 autogroup_def_t *agd = agi->agi_def;
871 autogroup_entry_t *age = agi->agi_entry;
872 autogroup_filter_t *agf;
873 BerValue new_dn, new_ndn, pdn;
876 int is_olddn, is_newdn, is_value_refresh, dn_equal;
878 /* Handle all cases where a refresh of the group is needed */
879 if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
880 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
882 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
884 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
885 /* Request detected that the group must be refreshed */
887 ldap_pvt_thread_mutex_lock( &age->age_mutex );
889 if ( age->age_mustrefresh ) {
890 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
892 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
893 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
897 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
900 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
903 if ( op->o_tag == LDAP_REQ_MODRDN ) {
904 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
906 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
908 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
910 if ( op->oq_modrdn.rs_newSup ) {
911 pdn = *op->oq_modrdn.rs_newSup;
913 dnParent( &op->o_req_dn, &pdn );
915 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
917 if ( op->oq_modrdn.rs_nnewSup ) {
918 pdn = *op->oq_modrdn.rs_nnewSup;
920 dnParent( &op->o_req_ndn, &pdn );
922 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
924 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
926 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
928 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
929 LDAP_SUCCESS || e == NULL ) {
930 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
931 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
932 return SLAP_CB_CONTINUE;
935 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
939 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
940 overlay_entry_release_ov( op, e, 0, on );
941 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
942 return SLAP_CB_CONTINUE;
946 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
947 for ( ; agd; agd = agd->agd_next ) {
949 if ( value_find_ex( slap_schema.si_ad_objectClass,
950 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
951 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
952 a->a_nvals, &agd->agd_oc->soc_cname,
953 op->o_tmpmemctx ) == 0 )
955 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
958 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
960 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
961 ber_dupbv( &age->age_dn, &new_dn );
962 ber_dupbv( &age->age_ndn, &new_ndn );
964 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
965 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
966 overlay_entry_release_ov( op, e, 0, on );
967 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
968 return SLAP_CB_CONTINUE;
975 overlay_entry_release_ov( op, e, 0, on );
978 1. check if the orginal entry's DN is in the group.
979 2. chceck if the any of the group filter's base DN is a suffix of the new DN
981 If 1 and 2 are both false, we do nothing.
982 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
983 If 1 is false, and 2 is true, we check the entry against the group's filters,
984 and add it's DN to the group.
985 If 1 is true, and 2 is false, we delete the entry's DN from the group.
987 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
990 is_value_refresh = 0;
993 ldap_pvt_thread_mutex_lock( &age->age_mutex );
995 if ( age->age_modrdn_olddnmodified ) {
996 /* Resquest already marked this group to be updated */
998 is_value_refresh = 1;
999 age->age_modrdn_olddnmodified = 0;
1002 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1003 LDAP_SUCCESS || group == NULL ) {
1004 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
1006 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1007 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1009 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1010 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1011 return SLAP_CB_CONTINUE;
1014 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1017 if ( value_find_ex( age->age_def->agd_member_ad,
1018 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1019 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1020 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1027 overlay_entry_release_ov( op, group, 0, on );
1031 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1032 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
1033 /* TODO: should retest filter as it could imply conditions on the dn */
1040 if ( is_value_refresh ) {
1041 if ( is_olddn != is_newdn ) {
1043 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1045 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1046 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1049 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1052 if ( is_olddn == 1 && is_newdn == 0 ) {
1053 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1055 if ( is_olddn == 0 && is_newdn == 1 ) {
1056 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
1057 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1058 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1063 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
1064 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1065 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1068 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1071 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1072 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1074 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1078 if ( op->o_tag == LDAP_REQ_MODIFY ) {
1079 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
1080 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
1082 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1084 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1085 LDAP_SUCCESS || e == NULL ) {
1086 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1087 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1088 return SLAP_CB_CONTINUE;
1091 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1095 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1096 overlay_entry_release_ov( op, e, 0, on );
1097 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1098 return SLAP_CB_CONTINUE;
1102 /* If we modify a group's memberURL, we have to delete all of it's members,
1103 and add them anew, because we cannot tell from which memberURL a member was added. */
1104 for ( ; agd; agd = agd->agd_next ) {
1106 if ( value_find_ex( slap_schema.si_ad_objectClass,
1107 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1108 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1109 a->a_nvals, &agd->agd_oc->soc_cname,
1110 op->o_tmpmemctx ) == 0 )
1115 m = op->orm_modlist;
1117 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1118 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1120 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1123 for ( ; m ; m = m->sml_next ) {
1124 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
1125 autogroup_def_t *group_agd = age->age_def;
1126 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
1127 op->o_req_dn.bv_val, 0, 0);
1129 overlay_entry_release_ov( op, e, 0, on );
1131 autogroup_delete_member_from_group( op, NULL, NULL, age );
1132 autogroup_delete_group( agi, age );
1134 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
1136 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1137 return SLAP_CB_CONTINUE;
1141 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1145 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1148 overlay_entry_release_ov( op, e, 0, on );
1149 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1150 return SLAP_CB_CONTINUE;
1154 overlay_entry_release_ov( op, e, 0, on );
1156 /* When modifing any of the attributes of an entry, we must
1157 check if the entry is in any of our groups, and if
1158 the modified entry maches any of the filters of that group.
1160 If the entry exists in a group, but the modified attributes do
1161 not match any of the group's filters, we delete the entry from that group.
1162 If the entry doesn't exist in a group, but matches a filter,
1163 we add it to that group.
1165 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1170 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1172 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1173 LDAP_SUCCESS || group == NULL ) {
1174 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
1175 age->age_dn.bv_val, 0, 0);
1177 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1178 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1179 return SLAP_CB_CONTINUE;
1182 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1185 if ( value_find_ex( age->age_def->agd_member_ad,
1186 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1187 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1188 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1195 overlay_entry_release_ov( op, group, 0, on );
1197 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1198 if ( !agf->agf_anlist && dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1199 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1206 if ( is_olddn == 1 && is_newdn == 0 ) {
1207 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1209 if ( is_olddn == 0 && is_newdn == 1 ) {
1210 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1213 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1216 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1220 return SLAP_CB_CONTINUE;
1224 ** When modifing a group, we must deny any modifications to the member attribute,
1225 ** because the group would be inconsistent.
1228 autogroup_modify_entry( Operation *op, SlapReply *rs)
1230 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1231 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1232 autogroup_def_t *agd = agi->agi_def;
1233 autogroup_entry_t *age = agi->agi_entry;
1237 if ( get_manageDSAit( op ) ) {
1238 return SLAP_CB_CONTINUE;
1241 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1242 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1244 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1245 LDAP_SUCCESS || e == NULL ) {
1246 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1247 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1248 return SLAP_CB_CONTINUE;
1251 /* Must refresh groups if a matching member value is modified */
1252 for ( ; age ; age = age->age_next ) {
1253 autogroup_filter_t *agf;
1254 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1255 if ( agf->agf_anlist ) {
1257 for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
1258 if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
1259 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1260 int rc = test_filter( op, e, agf->agf_filter );
1261 if ( rc == LDAP_COMPARE_TRUE ) {
1262 age->age_mustrefresh = 1;
1271 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1274 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1275 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1276 return SLAP_CB_CONTINUE;
1280 for ( ; agd; agd = agd->agd_next ) {
1282 if ( value_find_ex( slap_schema.si_ad_objectClass,
1283 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1284 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1285 a->a_nvals, &agd->agd_oc->soc_cname,
1286 op->o_tmpmemctx ) == 0 )
1291 m = op->orm_modlist;
1293 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1294 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1297 for ( ; m ; m = m->sml_next ) {
1298 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1299 overlay_entry_release_ov( op, e, 0, on );
1300 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1301 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1302 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1303 return LDAP_CONSTRAINT_VIOLATION;
1310 overlay_entry_release_ov( op, e, 0, on );
1311 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1312 return SLAP_CB_CONTINUE;
1316 overlay_entry_release_ov( op, e, 0, on );
1317 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1318 return SLAP_CB_CONTINUE;
1322 ** Detect if the olddn is part of a group and so if the group should be refreshed
1325 autogroup_modrdn_entry( Operation *op, SlapReply *rs)
1327 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1328 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1329 autogroup_entry_t *age = agi->agi_entry;
1332 if ( get_manageDSAit( op ) ) {
1333 return SLAP_CB_CONTINUE;
1336 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1337 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1339 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1340 LDAP_SUCCESS || e == NULL ) {
1341 Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1342 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1343 return SLAP_CB_CONTINUE;
1346 /* Must check if a dn is modified */
1347 for ( ; age ; age = age->age_next ) {
1348 autogroup_filter_t *agf;
1349 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1350 if ( agf->agf_anlist ) {
1351 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1352 int rc = test_filter( op, e, agf->agf_filter );
1353 if ( rc == LDAP_COMPARE_TRUE ) {
1354 age->age_modrdn_olddnmodified = 1;
1361 overlay_entry_release_ov( op, e, 0, on );
1362 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1363 return SLAP_CB_CONTINUE;
1367 ** Builds a filter for searching for the
1368 ** group entries, according to the objectClass.
1371 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1375 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1377 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1378 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1379 + agd->agd_oc->soc_cname.bv_len;
1380 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1382 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1384 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1388 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1390 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1400 static ConfigDriver ag_cfgen;
1402 static ConfigTable agcfg[] = {
1403 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1404 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1405 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1406 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1407 "EQUALITY caseIgnoreMatch "
1408 "SYNTAX OMsDirectoryString "
1409 "X-ORDERED 'VALUES' )",
1411 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1414 static ConfigOCs agocs[] = {
1415 { "( OLcfgCtOc:2.1 "
1416 "NAME 'olcAutomaticGroups' "
1417 "DESC 'Automatic groups configuration' "
1418 "SUP olcOverlayConfig "
1419 "MAY olcAGattrSet )",
1420 Cft_Overlay, agcfg, NULL, NULL },
1426 ag_cfgen( ConfigArgs *c )
1428 slap_overinst *on = (slap_overinst *)c->bi;
1429 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1430 autogroup_def_t *agd;
1431 autogroup_entry_t *age;
1435 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1438 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1439 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1440 agi->agi_def = NULL;
1441 agi->agi_entry = NULL;
1442 on->on_bi.bi_private = (void *)agi;
1446 age = agi->agi_entry;
1448 if ( c->op == SLAP_CONFIG_EMIT ) {
1450 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1452 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1454 char *ptr = c->cr_msg;
1456 assert(agd->agd_oc != NULL);
1457 assert(agd->agd_member_url_ad != NULL);
1458 assert(agd->agd_member_ad != NULL);
1460 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1461 SLAP_X_ORDERED_FMT "%s %s %s", i,
1462 agd->agd_oc->soc_cname.bv_val,
1463 agd->agd_member_url_ad->ad_cname.bv_val,
1464 agd->agd_member_ad->ad_cname.bv_val );
1466 bv.bv_val = c->cr_msg;
1467 bv.bv_len = ptr - bv.bv_val;
1468 value_add_one ( &c->rvalue_vals, &bv );
1471 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1475 }else if ( c->op == LDAP_MOD_DELETE ) {
1477 autogroup_def_t *agd_next;
1478 autogroup_entry_t *age_next;
1479 autogroup_filter_t *agf = age->age_filter,
1482 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1484 for ( agd_next = agd; agd_next; agd = agd_next ) {
1485 agd_next = agd->agd_next;
1490 for ( age_next = age ; age_next ; age = age_next ) {
1491 age_next = age->age_next;
1493 ch_free( age->age_dn.bv_val );
1494 ch_free( age->age_ndn.bv_val );
1496 for( agf_next = agf ; agf_next ; agf = agf_next ){
1497 agf_next = agf->agf_next;
1499 filter_free( agf->agf_filter );
1500 ch_free( agf->agf_filterstr.bv_val );
1501 ch_free( agf->agf_dn.bv_val );
1502 ch_free( agf->agf_ndn.bv_val );
1503 anlist_free( agf->agf_anlist, 1, NULL );
1507 ldap_pvt_thread_mutex_init( &age->age_mutex );
1511 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1513 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1515 on->on_bi.bi_private = NULL;
1518 autogroup_def_t **agdp;
1519 autogroup_entry_t *age_next, *age_prev;
1520 autogroup_filter_t *agf,
1523 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1525 for ( i = 0, agdp = &agi->agi_def;
1528 if ( *agdp == NULL) {
1531 agdp = &(*agdp)->agd_next;
1535 *agdp = agd->agd_next;
1537 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1538 age_next = age->age_next;
1540 if( age->age_def == agd ) {
1541 agf = age->age_filter;
1543 ch_free( age->age_dn.bv_val );
1544 ch_free( age->age_ndn.bv_val );
1546 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1547 agf_next = agf->agf_next;
1548 filter_free( agf->agf_filter );
1549 ch_free( agf->agf_filterstr.bv_val );
1550 ch_free( agf->agf_dn.bv_val );
1551 ch_free( agf->agf_ndn.bv_val );
1552 anlist_free( agf->agf_anlist, 1, NULL );
1556 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1561 if( age_prev != NULL ) {
1562 age_prev->age_next = age_next;
1569 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1578 autogroup_def_t **agdp,
1580 ObjectClass *oc = NULL;
1581 AttributeDescription *member_url_ad = NULL,
1586 oc = oc_find( c->argv[ 1 ] );
1588 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1589 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1590 "unable to find ObjectClass \"%s\"",
1592 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1593 c->log, c->cr_msg, 0 );
1598 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1599 if( rc != LDAP_SUCCESS ) {
1600 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1601 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1602 "unable to find AttributeDescription \"%s\"",
1604 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1605 c->log, c->cr_msg, 0 );
1609 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1610 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1611 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1612 "AttributeDescription \"%s\" ",
1613 "must be of a subtype \"labeledURI\"",
1615 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1616 c->log, c->cr_msg, 0 );
1620 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1621 if( rc != LDAP_SUCCESS ) {
1622 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1623 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1624 "unable to find AttributeDescription \"%s\"",
1626 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1627 c->log, c->cr_msg, 0 );
1631 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1633 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1634 /* The same URL attribute / member attribute pair
1635 * cannot be repeated */
1637 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1638 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1639 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1640 "URL attributeDescription \"%s\" already mapped",
1641 member_ad->ad_cname.bv_val );
1642 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1643 c->log, c->cr_msg, 0 );
1644 /* return 1; //warning*/
1648 if ( c->valx > 0 ) {
1651 for ( i = 0, agdp = &agi->agi_def ;
1654 if ( *agdp == NULL ) {
1655 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1656 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1657 "invalid index {%d}",
1659 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1660 c->log, c->cr_msg, 0 );
1662 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1665 agdp = &(*agdp)->agd_next;
1670 for ( agdp = &agi->agi_def; *agdp;
1671 agdp = &(*agdp)->agd_next )
1675 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1677 (*agdp)->agd_oc = oc;
1678 (*agdp)->agd_member_url_ad = member_url_ad;
1679 (*agdp)->agd_member_ad = member_ad;
1680 (*agdp)->agd_next = agd_next;
1682 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1695 ** Do a search for all the groups in the
1696 ** database, and add them to out internal list.
1703 slap_overinst *on = (slap_overinst *) be->bd_info;
1704 autogroup_info_t *agi = on->on_bi.bi_private;
1705 autogroup_def_t *agd;
1708 SlapReply rs = { REP_RESULT };
1709 slap_callback cb = { 0 };
1711 void *thrctx = ldap_pvt_thread_pool_context();
1712 Connection conn = { 0 };
1713 OperationBuffer opbuf;
1715 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1717 if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
1721 connection_fake_init( &conn, &opbuf, thrctx );
1724 op->ors_attrsonly = 0;
1725 op->o_tag = LDAP_REQ_SEARCH;
1726 op->o_dn = be->be_rootdn;
1727 op->o_ndn = be->be_rootndn;
1729 op->o_req_dn = be->be_suffix[0];
1730 op->o_req_ndn = be->be_nsuffix[0];
1732 op->ors_scope = LDAP_SCOPE_SUBTREE;
1733 op->ors_deref = LDAP_DEREF_NEVER;
1734 op->ors_limit = NULL;
1735 op->ors_tlimit = SLAP_NO_LIMIT;
1736 op->ors_slimit = SLAP_NO_LIMIT;
1737 op->ors_attrs = slap_anlist_no_attrs;
1740 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1743 cb.sc_private = &ags;
1744 cb.sc_response = autogroup_group_add_cb;
1745 cb.sc_cleanup = NULL;
1748 op->o_callback = &cb;
1750 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1752 autogroup_build_def_filter(agd, op);
1756 op->o_bd->be_search( op, &rs );
1758 filter_free_x( op, op->ors_filter, 1 );
1759 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1770 slap_overinst *on = (slap_overinst *) be->bd_info;
1772 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1774 if ( on->on_bi.bi_private ) {
1775 autogroup_info_t *agi = on->on_bi.bi_private;
1776 autogroup_entry_t *age = agi->agi_entry,
1778 autogroup_filter_t *agf, *agf_next;
1780 for ( age_next = age; age_next; age = age_next ) {
1781 age_next = age->age_next;
1783 ch_free( age->age_dn.bv_val );
1784 ch_free( age->age_ndn.bv_val );
1786 agf = age->age_filter;
1788 for ( agf_next = agf; agf_next; agf = agf_next ) {
1789 agf_next = agf->agf_next;
1791 filter_free( agf->agf_filter );
1792 ch_free( agf->agf_filterstr.bv_val );
1793 ch_free( agf->agf_dn.bv_val );
1794 ch_free( agf->agf_ndn.bv_val );
1795 anlist_free( agf->agf_anlist, 1, NULL );
1799 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1808 autogroup_db_destroy(
1812 slap_overinst *on = (slap_overinst *) be->bd_info;
1814 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1816 if ( on->on_bi.bi_private ) {
1817 autogroup_info_t *agi = on->on_bi.bi_private;
1818 autogroup_def_t *agd = agi->agi_def,
1821 for ( agd_next = agd; agd_next; agd = agd_next ) {
1822 agd_next = agd->agd_next;
1827 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1834 static slap_overinst autogroup = { { NULL } };
1838 autogroup_initialize(void)
1841 autogroup.on_bi.bi_type = "autogroup";
1843 autogroup.on_bi.bi_db_open = autogroup_db_open;
1844 autogroup.on_bi.bi_db_close = autogroup_db_close;
1845 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1847 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1848 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1849 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1850 autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
1852 autogroup.on_response = autogroup_response;
1854 autogroup.on_bi.bi_cf_ocs = agocs;
1856 rc = config_register_schema( agcfg, agocs );
1861 return overlay_register( &autogroup );
1865 init_module( int argc, char *argv[] )
1867 return autogroup_initialize();