1 /* autogroup.c - automatic group overlay */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2007-2010 The OpenLDAP Foundation.
6 * Portions Copyright 2007 Michał Szulczyński.
7 * Portions Copyright 2009 Howard Chu.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
19 * This work was initially developed by Michał Szulczyński for inclusion in
20 * OpenLDAP Software. Additional significant contributors include:
28 #include <ac/string.h>
34 /* Filter represents the memberURL of a group. */
35 typedef struct autogroup_filter_t {
36 struct berval agf_dn; /* The base DN in memberURL */
37 struct berval agf_ndn;
38 struct berval agf_filterstr;
41 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 assert( op->o_tag == LDAP_REQ_SEARCH );
271 if ( rs->sr_type == REP_SEARCH ) {
272 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
273 autogroup_entry_t *age = agg->agg_group;
274 autogroup_filter_t *agf = agg->agg_filter;
276 const char *text = NULL;
278 struct berval *vals, *nvals;
281 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
282 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
284 if ( agf->agf_anlist ) {
285 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
288 nvals = attr->a_nvals;
289 numvals = attr->a_numvals;
295 struct berval lvals[ 2 ], lnvals[ 2 ];
296 lvals[ 0 ] = rs->sr_entry->e_name;
297 BER_BVZERO( &lvals[ 1 ] );
298 lnvals[ 0 ] = rs->sr_entry->e_nname;
299 BER_BVZERO( &lnvals[ 1 ] );
305 mod.sm_op = LDAP_MOD_ADD;
306 mod.sm_desc = age->age_def->agd_member_ad;
307 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
308 mod.sm_values = vals;
309 mod.sm_nvalues = nvals;
310 mod.sm_numvals = numvals;
312 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
319 ** Callback used to add entries to a group, which is already in the database.
320 ** (used in on_response)
321 ** The group is passed in autogroup_ga_t->agg_group
325 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
327 assert( op->o_tag == LDAP_REQ_SEARCH );
329 if ( rs->sr_type == REP_SEARCH ) {
330 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
331 autogroup_entry_t *age = agg->agg_group;
332 autogroup_filter_t *agf = agg->agg_filter;
333 Modifications *modlist;
334 struct berval *vals, *nvals;
337 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
338 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
340 if ( agf->agf_anlist ) {
341 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
344 nvals = attr->a_nvals;
345 numvals = attr->a_numvals;
351 struct berval lvals[ 2 ], lnvals[ 2 ];
352 lvals[ 0 ] = rs->sr_entry->e_name;
353 BER_BVZERO( &lvals[ 1 ] );
354 lnvals[ 0 ] = rs->sr_entry->e_nname;
355 BER_BVZERO( &lnvals[ 1 ] );
362 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
364 modlist->sml_op = LDAP_MOD_ADD;
365 modlist->sml_desc = age->age_def->agd_member_ad;
366 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
368 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
369 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
370 modlist->sml_numvals = numvals;
372 modlist->sml_flags = SLAP_MOD_INTERNAL;
373 modlist->sml_next = NULL;
375 if ( agg->agg_mod == NULL ) {
376 agg->agg_mod = modlist;
377 agg->agg_mod_last = modlist;
379 agg->agg_mod_last->sml_next = modlist;
380 agg->agg_mod_last = modlist;
391 ** Adds all entries matching the passed filter to the specified group.
392 ** If modify == 1, then we modify the group's entry in the database using be_modify.
393 ** If modify == 0, then, we must supply a rw entry for the group,
394 ** because we only modify the entry, without calling be_modify.
395 ** e - the group entry, to which the members will be added
400 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
402 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
404 SlapReply rs = { REP_SEARCH };
405 slap_callback cb = { 0 };
406 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
409 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
410 age->age_dn.bv_val, 0, 0);
413 o.o_tag = LDAP_REQ_SEARCH;
415 o.o_req_dn = agf->agf_dn;
416 o.o_req_ndn = agf->agf_ndn;
418 o.ors_filterstr = agf->agf_filterstr;
419 o.ors_filter = agf->agf_filter;
421 o.ors_scope = agf->agf_scope;
422 o.ors_deref = LDAP_DEREF_NEVER;
424 o.ors_tlimit = SLAP_NO_LIMIT;
425 o.ors_slimit = SLAP_NO_LIMIT;
426 o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
429 agg.agg_filter = agf;
431 agg.agg_mod_last = NULL;
433 cb.sc_private = &agg;
436 cb.sc_response = autogroup_member_search_modify_cb;
438 cb.sc_response = autogroup_member_search_cb;
441 cb.sc_cleanup = NULL;
446 o.o_bd->bd_info = (BackendInfo *)on->on_info;
447 op->o_bd->be_search( &o, &rs );
448 o.o_bd->bd_info = (BackendInfo *)on;
450 if ( modify == 1 && agg.agg_mod ) {
452 o.o_callback = &null_cb;
453 o.o_tag = LDAP_REQ_MODIFY;
454 o.orm_modlist = agg.agg_mod;
455 o.o_req_dn = age->age_dn;
456 o.o_req_ndn = age->age_ndn;
457 o.o_relax = SLAP_CONTROL_CRITICAL;
458 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
459 o.o_permissive_modify = 1;
461 o.o_bd->bd_info = (BackendInfo *)on->on_info;
462 (void)op->o_bd->be_modify( &o, &rs );
463 o.o_bd->bd_info = (BackendInfo *)on;
465 slap_mods_free(agg.agg_mod, 1);
472 ** Adds a group to the internal list from the passed entry.
473 ** scan specifies whether to add all maching members to the group.
474 ** modify specifies whether to modify the given group entry (when modify == 0),
475 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
476 ** agi - pointer to the groups and the attribute definitions
477 ** agd - the attribute definition of the added group
478 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
479 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
482 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
484 autogroup_entry_t **agep = &agi->agi_entry;
485 autogroup_filter_t *agf, *agf_prev = NULL;
486 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
487 LDAPURLDesc *lud = NULL;
490 int rc = 0, match = 1, null_entry = 0;
493 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
494 LDAP_SUCCESS || e == NULL ) {
495 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
502 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
503 e->e_name.bv_val, 0, 0);
505 if ( agi->agi_entry != NULL ) {
506 for ( ; *agep ; agep = &(*agep)->age_next ) {
507 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
509 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
517 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
518 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
519 (*agep)->age_def = agd;
520 (*agep)->age_filter = NULL;
521 (*agep)->age_mustrefresh = 0;
522 (*agep)->age_modrdn_olddnmodified = 0;
524 ber_dupbv( &(*agep)->age_dn, &e->e_name );
525 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
527 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
529 if ( null_entry == 1 ) {
531 overlay_entry_release_ov( op, e, 0, on );
535 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
537 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
539 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
541 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
542 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
548 agf->agf_scope = lud->lud_scope;
550 if ( lud->lud_dn == NULL ) {
551 BER_BVSTR( &dn, "" );
553 ber_str2bv( lud->lud_dn, 0, 0, &dn );
556 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
557 if ( rc != LDAP_SUCCESS ) {
558 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
563 if ( lud->lud_filter != NULL ) {
564 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
565 agf->agf_filter = str2filter( lud->lud_filter );
568 if ( lud->lud_attrs != NULL ) {
571 for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
576 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: to much attributes specified in url <%s>\n",
579 ldap_free_urldesc( lud );
583 agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
585 if ( agf->agf_anlist == NULL ) {
586 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
587 lud->lud_attrs[0], 0, 0 );
589 ldap_free_urldesc( lud );
595 agf->agf_next = NULL;
598 if( (*agep)->age_filter == NULL ) {
599 (*agep)->age_filter = agf;
602 if( agf_prev != NULL ) {
603 agf_prev->agf_next = agf;
609 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
612 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
613 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
615 ldap_free_urldesc( lud );
622 ldap_free_urldesc( lud );
627 if ( null_entry == 1 ) {
634 ** Used when opening the database to add all existing
635 ** groups from the database to our internal list.
638 autogroup_group_add_cb( Operation *op, SlapReply *rs )
640 assert( op->o_tag == LDAP_REQ_SEARCH );
642 if ( rs->sr_type == REP_SEARCH ) {
643 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
645 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
646 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
648 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
656 ** When adding a group, we first strip any existing members,
657 ** and add all which match the filters ourselfs.
660 autogroup_add_entry( Operation *op, SlapReply *rs)
662 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
663 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
664 autogroup_def_t *agd = agi->agi_def;
665 autogroup_entry_t *age = agi->agi_entry;
666 autogroup_filter_t *agf;
669 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
670 op->ora_e->e_name.bv_val, 0, 0);
672 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
674 /* Check if it's a group. */
675 for ( ; agd ; agd = agd->agd_next ) {
676 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
678 const char *text = NULL;
681 mod.sm_op = LDAP_MOD_DELETE;
682 mod.sm_desc = agd->agd_member_ad;
683 mod.sm_type = agd->agd_member_ad->ad_cname;
684 mod.sm_values = NULL;
685 mod.sm_nvalues = NULL;
687 /* We don't want any member attributes added by the user. */
688 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
690 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
691 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
692 return SLAP_CB_CONTINUE;
696 for ( ; age ; age = age->age_next ) {
697 ldap_pvt_thread_mutex_lock( &age->age_mutex );
699 /* Check if any of the filters are the suffix to the entry DN.
700 If yes, we can test that filter against the entry. */
702 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
703 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
704 rc = test_filter( op, op->ora_e, agf->agf_filter );
705 if ( rc == LDAP_COMPARE_TRUE ) {
706 if ( agf->agf_anlist ) {
707 autogroup_add_member_values_to_group( op, op->ora_e, age, agf->agf_anlist[0].an_desc );
709 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
715 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
718 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
720 return SLAP_CB_CONTINUE;
724 ** agi - internal group and attribute definitions list
725 ** e - the group to remove from the internal list
728 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
730 autogroup_entry_t *age = agi->agi_entry,
735 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
736 age->age_dn.bv_val, 0, 0);
738 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
739 age_next = age->age_next;
742 autogroup_filter_t *agf = age->age_filter,
745 if ( age_prev != NULL ) {
746 age_prev->age_next = age_next;
748 agi->agi_entry = NULL;
751 ch_free( age->age_dn.bv_val );
752 ch_free( age->age_ndn.bv_val );
754 for( agf_next = agf ; agf_next ; agf = agf_next ){
755 agf_next = agf->agf_next;
757 filter_free( agf->agf_filter );
758 ch_free( agf->agf_filterstr.bv_val );
759 ch_free( agf->agf_dn.bv_val );
760 ch_free( agf->agf_ndn.bv_val );
761 anlist_free( agf->agf_anlist, 1, NULL );
765 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
766 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
775 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
782 autogroup_delete_entry( Operation *op, SlapReply *rs)
784 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
785 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
786 autogroup_entry_t *age = agi->agi_entry,
787 *age_prev, *age_next;
788 autogroup_filter_t *agf;
790 int matched_group = 0, rc = 0;
792 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
794 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
796 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
797 LDAP_SUCCESS || e == NULL ) {
798 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
799 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
800 return SLAP_CB_CONTINUE;
803 /* Check if the entry to be deleted is one of our groups. */
804 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
805 ldap_pvt_thread_mutex_lock( &age->age_mutex );
806 age_next = age->age_next;
808 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
813 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
816 autogroup_delete_group( agi, age );
821 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
824 if ( matched_group == 1 ) {
825 overlay_entry_release_ov( op, e, 0, on );
826 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
827 return SLAP_CB_CONTINUE;
830 /* Check if the entry matches any of the groups.
831 If yes, we can delete the entry from that group. */
833 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
834 ldap_pvt_thread_mutex_lock( &age->age_mutex );
836 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
837 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
838 rc = test_filter( op, e, agf->agf_filter );
839 if ( rc == LDAP_COMPARE_TRUE ) {
840 /* If the attribute is retrieved from the entry, we don't know what to delete
841 ** So the group must be entirely refreshed
842 ** But the refresh can't be done now because the entry is not deleted
843 ** So the group is marked as mustrefresh
845 if ( agf->agf_anlist ) {
846 age->age_mustrefresh = 1;
848 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
854 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
857 overlay_entry_release_ov( op, e, 0, on );
858 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
860 return SLAP_CB_CONTINUE;
864 autogroup_response( Operation *op, SlapReply *rs )
866 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
867 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
868 autogroup_def_t *agd = agi->agi_def;
869 autogroup_entry_t *age = agi->agi_entry;
870 autogroup_filter_t *agf;
871 BerValue new_dn, new_ndn, pdn;
874 int is_olddn, is_newdn, is_value_refresh, dn_equal;
876 /* Handle all cases where a refresh of the group is needed */
877 if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
878 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
880 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
882 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
883 /* Request detected that the group must be refreshed */
885 ldap_pvt_thread_mutex_lock( &age->age_mutex );
887 if ( age->age_mustrefresh ) {
888 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
890 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
891 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
895 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
898 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
901 if ( op->o_tag == LDAP_REQ_MODRDN ) {
902 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
904 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
906 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
908 if ( op->oq_modrdn.rs_newSup ) {
909 pdn = *op->oq_modrdn.rs_newSup;
911 dnParent( &op->o_req_dn, &pdn );
913 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
915 if ( op->oq_modrdn.rs_nnewSup ) {
916 pdn = *op->oq_modrdn.rs_nnewSup;
918 dnParent( &op->o_req_ndn, &pdn );
920 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
922 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
924 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
926 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
927 LDAP_SUCCESS || e == NULL ) {
928 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
929 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
930 return SLAP_CB_CONTINUE;
933 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
937 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
938 overlay_entry_release_ov( op, e, 0, on );
939 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
940 return SLAP_CB_CONTINUE;
944 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
945 for ( ; agd; agd = agd->agd_next ) {
947 if ( value_find_ex( slap_schema.si_ad_objectClass,
948 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
949 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
950 a->a_nvals, &agd->agd_oc->soc_cname,
951 op->o_tmpmemctx ) == 0 )
953 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
956 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
958 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
959 ber_dupbv( &age->age_dn, &new_dn );
960 ber_dupbv( &age->age_ndn, &new_ndn );
962 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
963 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
964 overlay_entry_release_ov( op, e, 0, on );
965 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
966 return SLAP_CB_CONTINUE;
973 overlay_entry_release_ov( op, e, 0, on );
976 1. check if the orginal entry's DN is in the group.
977 2. chceck if the any of the group filter's base DN is a suffix of the new DN
979 If 1 and 2 are both false, we do nothing.
980 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
981 If 1 is false, and 2 is true, we check the entry against the group's filters,
982 and add it's DN to the group.
983 If 1 is true, and 2 is false, we delete the entry's DN from the group.
985 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
988 is_value_refresh = 0;
991 ldap_pvt_thread_mutex_lock( &age->age_mutex );
993 if ( age->age_modrdn_olddnmodified ) {
994 /* Resquest already marked this group to be updated */
996 is_value_refresh = 1;
997 age->age_modrdn_olddnmodified = 0;
1000 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1001 LDAP_SUCCESS || group == NULL ) {
1002 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
1004 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1005 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1007 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1008 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1009 return SLAP_CB_CONTINUE;
1012 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1015 if ( value_find_ex( age->age_def->agd_member_ad,
1016 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1017 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1018 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1025 overlay_entry_release_ov( op, group, 0, on );
1029 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1030 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
1031 /* TODO: should retest filter as it could imply conditions on the dn */
1038 if ( is_value_refresh ) {
1039 if ( is_olddn != is_newdn ) {
1041 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1043 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1044 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1047 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1050 if ( is_olddn == 1 && is_newdn == 0 ) {
1051 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1053 if ( is_olddn == 0 && is_newdn == 1 ) {
1054 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
1055 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1056 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1061 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
1062 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1063 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1066 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1069 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1070 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1072 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1076 if ( op->o_tag == LDAP_REQ_MODIFY ) {
1077 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
1078 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
1080 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1082 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1083 LDAP_SUCCESS || e == NULL ) {
1084 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1085 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1086 return SLAP_CB_CONTINUE;
1089 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1093 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1094 overlay_entry_release_ov( op, e, 0, on );
1095 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1096 return SLAP_CB_CONTINUE;
1100 /* If we modify a group's memberURL, we have to delete all of it's members,
1101 and add them anew, because we cannot tell from which memberURL a member was added. */
1102 for ( ; agd; agd = agd->agd_next ) {
1104 if ( value_find_ex( slap_schema.si_ad_objectClass,
1105 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1106 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1107 a->a_nvals, &agd->agd_oc->soc_cname,
1108 op->o_tmpmemctx ) == 0 )
1113 m = op->orm_modlist;
1115 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1116 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1118 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1121 for ( ; m ; m = m->sml_next ) {
1122 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
1123 autogroup_def_t *group_agd = age->age_def;
1124 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
1125 op->o_req_dn.bv_val, 0, 0);
1127 overlay_entry_release_ov( op, e, 0, on );
1129 autogroup_delete_member_from_group( op, NULL, NULL, age );
1130 autogroup_delete_group( agi, age );
1132 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
1134 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1135 return SLAP_CB_CONTINUE;
1139 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1143 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1146 overlay_entry_release_ov( op, e, 0, on );
1147 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1148 return SLAP_CB_CONTINUE;
1152 overlay_entry_release_ov( op, e, 0, on );
1154 /* When modifing any of the attributes of an entry, we must
1155 check if the entry is in any of our groups, and if
1156 the modified entry maches any of the filters of that group.
1158 If the entry exists in a group, but the modified attributes do
1159 not match any of the group's filters, we delete the entry from that group.
1160 If the entry doesn't exist in a group, but matches a filter,
1161 we add it to that group.
1163 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1168 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1170 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1171 LDAP_SUCCESS || group == NULL ) {
1172 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
1173 age->age_dn.bv_val, 0, 0);
1175 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1176 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1177 return SLAP_CB_CONTINUE;
1180 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1183 if ( value_find_ex( age->age_def->agd_member_ad,
1184 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1185 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1186 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1193 overlay_entry_release_ov( op, group, 0, on );
1195 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1196 if ( !agf->agf_anlist && dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1197 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1204 if ( is_olddn == 1 && is_newdn == 0 ) {
1205 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1207 if ( is_olddn == 0 && is_newdn == 1 ) {
1208 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1211 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1214 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1218 return SLAP_CB_CONTINUE;
1222 ** When modifing a group, we must deny any modifications to the member attribute,
1223 ** because the group would be inconsistent.
1226 autogroup_modify_entry( Operation *op, SlapReply *rs)
1228 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1229 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1230 autogroup_def_t *agd = agi->agi_def;
1231 autogroup_entry_t *age = agi->agi_entry;
1235 if ( get_manageDSAit( op ) ) {
1236 return SLAP_CB_CONTINUE;
1239 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1240 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1242 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1243 LDAP_SUCCESS || e == NULL ) {
1244 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1245 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1246 return SLAP_CB_CONTINUE;
1249 /* Must refresh groups if a matching member value is modified */
1250 for ( ; age ; age = age->age_next ) {
1251 autogroup_filter_t *agf;
1252 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1253 if ( agf->agf_anlist ) {
1255 for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
1256 if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
1257 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1258 int rc = test_filter( op, e, agf->agf_filter );
1259 if ( rc == LDAP_COMPARE_TRUE ) {
1260 age->age_mustrefresh = 1;
1269 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1272 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1273 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1274 return SLAP_CB_CONTINUE;
1278 for ( ; agd; agd = agd->agd_next ) {
1280 if ( value_find_ex( slap_schema.si_ad_objectClass,
1281 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1282 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1283 a->a_nvals, &agd->agd_oc->soc_cname,
1284 op->o_tmpmemctx ) == 0 )
1289 m = op->orm_modlist;
1291 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1292 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1295 for ( ; m ; m = m->sml_next ) {
1296 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1297 overlay_entry_release_ov( op, e, 0, on );
1298 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1299 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1300 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1301 return LDAP_CONSTRAINT_VIOLATION;
1308 overlay_entry_release_ov( op, e, 0, on );
1309 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1310 return SLAP_CB_CONTINUE;
1314 overlay_entry_release_ov( op, e, 0, on );
1315 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1316 return SLAP_CB_CONTINUE;
1320 ** Detect if the olddn is part of a group and so if the group should be refreshed
1323 autogroup_modrdn_entry( Operation *op, SlapReply *rs)
1325 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1326 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1327 autogroup_entry_t *age = agi->agi_entry;
1330 if ( get_manageDSAit( op ) ) {
1331 return SLAP_CB_CONTINUE;
1334 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1335 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1337 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1338 LDAP_SUCCESS || e == NULL ) {
1339 Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1340 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1341 return SLAP_CB_CONTINUE;
1344 /* Must check if a dn is modified */
1345 for ( ; age ; age = age->age_next ) {
1346 autogroup_filter_t *agf;
1347 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1348 if ( agf->agf_anlist ) {
1349 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1350 int rc = test_filter( op, e, agf->agf_filter );
1351 if ( rc == LDAP_COMPARE_TRUE ) {
1352 age->age_modrdn_olddnmodified = 1;
1359 overlay_entry_release_ov( op, e, 0, on );
1360 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1361 return SLAP_CB_CONTINUE;
1365 ** Builds a filter for searching for the
1366 ** group entries, according to the objectClass.
1369 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1373 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1375 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1376 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1377 + agd->agd_oc->soc_cname.bv_len;
1378 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1380 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1382 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1386 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1388 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1398 static ConfigDriver ag_cfgen;
1400 static ConfigTable agcfg[] = {
1401 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1402 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1403 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1404 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1405 "EQUALITY caseIgnoreMatch "
1406 "SYNTAX OMsDirectoryString "
1407 "X-ORDERED 'VALUES' )",
1409 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1412 static ConfigOCs agocs[] = {
1413 { "( OLcfgCtOc:2.1 "
1414 "NAME 'olcAutomaticGroups' "
1415 "DESC 'Automatic groups configuration' "
1416 "SUP olcOverlayConfig "
1417 "MAY olcAGattrSet )",
1418 Cft_Overlay, agcfg, NULL, NULL },
1424 ag_cfgen( ConfigArgs *c )
1426 slap_overinst *on = (slap_overinst *)c->bi;
1427 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1428 autogroup_def_t *agd;
1429 autogroup_entry_t *age;
1433 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1436 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1437 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1438 agi->agi_def = NULL;
1439 agi->agi_entry = NULL;
1440 on->on_bi.bi_private = (void *)agi;
1444 age = agi->agi_entry;
1446 if ( c->op == SLAP_CONFIG_EMIT ) {
1448 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1450 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1452 char *ptr = c->cr_msg;
1454 assert(agd->agd_oc != NULL);
1455 assert(agd->agd_member_url_ad != NULL);
1456 assert(agd->agd_member_ad != NULL);
1458 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1459 SLAP_X_ORDERED_FMT "%s %s %s", i,
1460 agd->agd_oc->soc_cname.bv_val,
1461 agd->agd_member_url_ad->ad_cname.bv_val,
1462 agd->agd_member_ad->ad_cname.bv_val );
1464 bv.bv_val = c->cr_msg;
1465 bv.bv_len = ptr - bv.bv_val;
1466 value_add_one ( &c->rvalue_vals, &bv );
1469 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1473 }else if ( c->op == LDAP_MOD_DELETE ) {
1475 autogroup_def_t *agd_next;
1476 autogroup_entry_t *age_next;
1477 autogroup_filter_t *agf = age->age_filter,
1480 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1482 for ( agd_next = agd; agd_next; agd = agd_next ) {
1483 agd_next = agd->agd_next;
1488 for ( age_next = age ; age_next ; age = age_next ) {
1489 age_next = age->age_next;
1491 ch_free( age->age_dn.bv_val );
1492 ch_free( age->age_ndn.bv_val );
1494 for( agf_next = agf ; agf_next ; agf = agf_next ){
1495 agf_next = agf->agf_next;
1497 filter_free( agf->agf_filter );
1498 ch_free( agf->agf_filterstr.bv_val );
1499 ch_free( agf->agf_dn.bv_val );
1500 ch_free( agf->agf_ndn.bv_val );
1501 anlist_free( agf->agf_anlist, 1, NULL );
1505 ldap_pvt_thread_mutex_init( &age->age_mutex );
1509 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1511 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1513 on->on_bi.bi_private = NULL;
1516 autogroup_def_t **agdp;
1517 autogroup_entry_t *age_next, *age_prev;
1518 autogroup_filter_t *agf,
1521 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1523 for ( i = 0, agdp = &agi->agi_def;
1526 if ( *agdp == NULL) {
1529 agdp = &(*agdp)->agd_next;
1533 *agdp = agd->agd_next;
1535 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1536 age_next = age->age_next;
1538 if( age->age_def == agd ) {
1539 agf = age->age_filter;
1541 ch_free( age->age_dn.bv_val );
1542 ch_free( age->age_ndn.bv_val );
1544 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1545 agf_next = agf->agf_next;
1546 filter_free( agf->agf_filter );
1547 ch_free( agf->agf_filterstr.bv_val );
1548 ch_free( agf->agf_dn.bv_val );
1549 ch_free( agf->agf_ndn.bv_val );
1550 anlist_free( agf->agf_anlist, 1, NULL );
1554 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1559 if( age_prev != NULL ) {
1560 age_prev->age_next = age_next;
1567 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1576 autogroup_def_t **agdp,
1578 ObjectClass *oc = NULL;
1579 AttributeDescription *member_url_ad = NULL,
1584 oc = oc_find( c->argv[ 1 ] );
1586 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1587 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1588 "unable to find ObjectClass \"%s\"",
1590 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1591 c->log, c->cr_msg, 0 );
1596 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1597 if( rc != LDAP_SUCCESS ) {
1598 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1599 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1600 "unable to find AttributeDescription \"%s\"",
1602 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1603 c->log, c->cr_msg, 0 );
1607 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1608 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1609 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1610 "AttributeDescription \"%s\" ",
1611 "must be of a subtype \"labeledURI\"",
1613 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1614 c->log, c->cr_msg, 0 );
1618 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1619 if( rc != LDAP_SUCCESS ) {
1620 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1621 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1622 "unable to find AttributeDescription \"%s\"",
1624 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1625 c->log, c->cr_msg, 0 );
1629 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1631 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1632 /* The same URL attribute / member attribute pair
1633 * cannot be repeated */
1635 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1636 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1637 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1638 "URL attributeDescription \"%s\" already mapped",
1639 member_ad->ad_cname.bv_val );
1640 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1641 c->log, c->cr_msg, 0 );
1642 /* return 1; //warning*/
1646 if ( c->valx > 0 ) {
1649 for ( i = 0, agdp = &agi->agi_def ;
1652 if ( *agdp == NULL ) {
1653 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1654 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1655 "invalid index {%d}",
1657 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1658 c->log, c->cr_msg, 0 );
1660 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1663 agdp = &(*agdp)->agd_next;
1668 for ( agdp = &agi->agi_def; *agdp;
1669 agdp = &(*agdp)->agd_next )
1673 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1675 (*agdp)->agd_oc = oc;
1676 (*agdp)->agd_member_url_ad = member_url_ad;
1677 (*agdp)->agd_member_ad = member_ad;
1678 (*agdp)->agd_next = agd_next;
1680 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1693 ** Do a search for all the groups in the
1694 ** database, and add them to out internal list.
1701 slap_overinst *on = (slap_overinst *) be->bd_info;
1702 autogroup_info_t *agi = on->on_bi.bi_private;
1703 autogroup_def_t *agd;
1706 SlapReply rs = { REP_RESULT };
1707 slap_callback cb = { 0 };
1709 void *thrctx = ldap_pvt_thread_pool_context();
1710 Connection conn = { 0 };
1711 OperationBuffer opbuf;
1713 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1715 if ( agi == NULL ) {
1719 connection_fake_init( &conn, &opbuf, thrctx );
1722 op->ors_attrsonly = 0;
1723 op->o_tag = LDAP_REQ_SEARCH;
1724 op->o_dn = be->be_rootdn;
1725 op->o_ndn = be->be_rootndn;
1727 op->o_req_dn = be->be_suffix[0];
1728 op->o_req_ndn = be->be_nsuffix[0];
1730 op->ors_scope = LDAP_SCOPE_SUBTREE;
1731 op->ors_deref = LDAP_DEREF_NEVER;
1732 op->ors_limit = NULL;
1733 op->ors_tlimit = SLAP_NO_LIMIT;
1734 op->ors_slimit = SLAP_NO_LIMIT;
1735 op->ors_attrs = slap_anlist_no_attrs;
1738 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1741 cb.sc_private = &ags;
1742 cb.sc_response = autogroup_group_add_cb;
1743 cb.sc_cleanup = NULL;
1746 op->o_callback = &cb;
1748 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1750 autogroup_build_def_filter(agd, op);
1754 op->o_bd->be_search( op, &rs );
1756 filter_free_x( op, op->ors_filter, 1 );
1757 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1768 slap_overinst *on = (slap_overinst *) be->bd_info;
1770 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1772 if ( on->on_bi.bi_private ) {
1773 autogroup_info_t *agi = on->on_bi.bi_private;
1774 autogroup_entry_t *age = agi->agi_entry,
1776 autogroup_filter_t *agf, *agf_next;
1778 for ( age_next = age; age_next; age = age_next ) {
1779 age_next = age->age_next;
1781 ch_free( age->age_dn.bv_val );
1782 ch_free( age->age_ndn.bv_val );
1784 agf = age->age_filter;
1786 for ( agf_next = agf; agf_next; agf = agf_next ) {
1787 agf_next = agf->agf_next;
1789 filter_free( agf->agf_filter );
1790 ch_free( agf->agf_filterstr.bv_val );
1791 ch_free( agf->agf_dn.bv_val );
1792 ch_free( agf->agf_ndn.bv_val );
1793 anlist_free( agf->agf_anlist, 1, NULL );
1797 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1806 autogroup_db_destroy(
1810 slap_overinst *on = (slap_overinst *) be->bd_info;
1812 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1814 if ( on->on_bi.bi_private ) {
1815 autogroup_info_t *agi = on->on_bi.bi_private;
1816 autogroup_def_t *agd = agi->agi_def,
1819 for ( agd_next = agd; agd_next; agd = agd_next ) {
1820 agd_next = agd->agd_next;
1825 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1832 static slap_overinst autogroup = { { NULL } };
1836 autogroup_initialize(void)
1839 autogroup.on_bi.bi_type = "autogroup";
1841 autogroup.on_bi.bi_db_open = autogroup_db_open;
1842 autogroup.on_bi.bi_db_close = autogroup_db_close;
1843 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1845 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1846 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1847 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1848 autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
1850 autogroup.on_response = autogroup_response;
1852 autogroup.on_bi.bi_cf_ocs = agocs;
1854 rc = config_register_schema( agcfg, agocs );
1859 return overlay_register( &autogroup );
1863 init_module( int argc, char *argv[] )
1865 return autogroup_initialize();