autogroup.c revision 1.1.1.2 1 /* $NetBSD: autogroup.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */
2
3 /* autogroup.c - automatic group overlay */
4 /* OpenLDAP: pkg/ldap/contrib/slapd-modules/autogroup/autogroup.c,v 1.2.2.5 2009/09/29 21:52:13 quanah Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2007-2009 The OpenLDAP Foundation.
8 * Portions Copyright 2007 Micha Szulczyski.
9 * Portions Copyright 2009 Howard Chu.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted only as authorized by the OpenLDAP
14 * Public License.
15 *
16 * A copy of this license is available in the file LICENSE in the
17 * top-level directory of the distribution or, alternatively, at
18 * <http://www.OpenLDAP.org/license.html>.
19 */
20 /* ACKNOWLEDGEMENTS:
21 * This work was initially developed by Micha Szulczyski for inclusion in
22 * OpenLDAP Software. Additional significant contributors include:
23 * Howard Chu
24 */
25
26 #include "portable.h"
27
28 #include <stdio.h>
29
30 #include <ac/string.h>
31
32 #include "slap.h"
33 #include "config.h"
34 #include "lutil.h"
35
36 /* Filter represents the memberURL of a group. */
37 typedef struct autogroup_filter_t {
38 struct berval agf_dn; /* The base DN in memberURL */
39 struct berval agf_ndn;
40 struct berval agf_filterstr;
41 Filter *agf_filter;
42 int agf_scope;
43 struct autogroup_filter_t *agf_next;
44 } autogroup_filter_t;
45
46 /* Description of group attributes. */
47 typedef struct autogroup_def_t {
48 ObjectClass *agd_oc;
49 AttributeDescription *agd_member_url_ad;
50 AttributeDescription *agd_member_ad;
51 struct autogroup_def_t *agd_next;
52 } autogroup_def_t;
53
54 /* Represents the group entry. */
55 typedef struct autogroup_entry_t {
56 BerValue age_dn;
57 BerValue age_ndn;
58 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
59 autogroup_def_t *age_def; /* Attribute definition */
60 ldap_pvt_thread_mutex_t age_mutex;
61 struct autogroup_entry_t *age_next;
62 } autogroup_entry_t;
63
64 /* Holds pointers to attribute definitions and groups. */
65 typedef struct autogroup_info_t {
66 autogroup_def_t *agi_def; /* Group attributes definitions. */
67 autogroup_entry_t *agi_entry; /* Group entries. */
68 ldap_pvt_thread_mutex_t agi_mutex;
69 } autogroup_info_t;
70
71 /* Search callback for adding groups initially. */
72 typedef struct autogroup_sc_t {
73 autogroup_info_t *ags_info; /* Group definitions and entries. */
74 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
75 } autogroup_sc_t;
76
77 /* Used for adding members, found when searching, to a group. */
78 typedef struct autogroup_ga_t {
79 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
80 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
81 this entry with the search results. */
82
83 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
84 search results which will be added to the group. */
85
86 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
87 have to search for the last mod added. */
88 } autogroup_ga_t;
89
90
91 /*
92 ** dn, ndn - the DN of the member to add
93 ** age - the group to which the member DN will be added
94 */
95 static int
96 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
97 {
98 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
99 Modifications modlist;
100 SlapReply sreply = {REP_RESULT};
101 BerValue vals[ 2 ], nvals[ 2 ];
102 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
103 Operation o = *op;
104
105 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
106 dn->bv_val, age->age_dn.bv_val, 0);
107
108 assert( dn != NULL );
109 assert( ndn != NULL );
110
111 vals[ 0 ] = *dn;
112 BER_BVZERO( &vals[ 1 ] );
113 nvals[ 0 ] = *ndn;
114 BER_BVZERO( &nvals[ 1 ] );
115
116 modlist.sml_op = LDAP_MOD_ADD;
117 modlist.sml_desc = age->age_def->agd_member_ad;
118 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
119 modlist.sml_values = vals;
120 modlist.sml_nvalues = nvals;
121 modlist.sml_numvals = 1;
122 modlist.sml_flags = SLAP_MOD_INTERNAL;
123 modlist.sml_next = NULL;
124
125 o.o_tag = LDAP_REQ_MODIFY;
126 o.o_callback = &cb;
127 o.orm_modlist = &modlist;
128 o.o_req_dn = age->age_dn;
129 o.o_req_ndn = age->age_ndn;
130 o.o_permissive_modify = 1;
131 o.o_managedsait = SLAP_CONTROL_CRITICAL;
132 o.o_relax = SLAP_CONTROL_CRITICAL;
133
134 o.o_bd->bd_info = (BackendInfo *)on->on_info;
135 (void)op->o_bd->be_modify( &o, &sreply );
136 o.o_bd->bd_info = (BackendInfo *)on;
137
138 return sreply.sr_err;
139 }
140
141 /*
142 ** dn,ndn - the DN to be deleted
143 ** age - the group from which the DN will be deleted
144 ** If we pass a NULL dn and ndn, all members are deleted from the group.
145 */
146 static int
147 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
148 {
149 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
150 Modifications modlist;
151 SlapReply sreply = {REP_RESULT};
152 BerValue vals[ 2 ], nvals[ 2 ];
153 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
154 Operation o = *op;
155
156 if ( dn == NULL || ndn == NULL ) {
157 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
158 age->age_dn.bv_val, 0 ,0);
159
160 modlist.sml_values = NULL;
161 modlist.sml_nvalues = NULL;
162 modlist.sml_numvals = 0;
163 } else {
164 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
165 dn->bv_val, age->age_dn.bv_val, 0);
166
167 vals[ 0 ] = *dn;
168 BER_BVZERO( &vals[ 1 ] );
169 nvals[ 0 ] = *ndn;
170 BER_BVZERO( &nvals[ 1 ] );
171
172 modlist.sml_values = vals;
173 modlist.sml_nvalues = nvals;
174 modlist.sml_numvals = 1;
175 }
176
177
178 modlist.sml_op = LDAP_MOD_DELETE;
179 modlist.sml_desc = age->age_def->agd_member_ad;
180 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
181 modlist.sml_flags = SLAP_MOD_INTERNAL;
182 modlist.sml_next = NULL;
183
184 o.o_callback = &cb;
185 o.o_tag = LDAP_REQ_MODIFY;
186 o.orm_modlist = &modlist;
187 o.o_req_dn = age->age_dn;
188 o.o_req_ndn = age->age_ndn;
189 o.o_relax = SLAP_CONTROL_CRITICAL;
190 o.o_managedsait = SLAP_CONTROL_CRITICAL;
191 o.o_permissive_modify = 1;
192
193 o.o_bd->bd_info = (BackendInfo *)on->on_info;
194 (void)op->o_bd->be_modify( &o, &sreply );
195 o.o_bd->bd_info = (BackendInfo *)on;
196
197 return sreply.sr_err;
198 }
199
200 /*
201 ** Callback used to add entries to a group,
202 ** which are going to be written in the database
203 ** (used in bi_op_add)
204 ** The group is passed in autogroup_ga_t->agg_group
205 */
206 static int
207 autogroup_member_search_cb( Operation *op, SlapReply *rs )
208 {
209 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
210
211 assert( op->o_tag == LDAP_REQ_SEARCH );
212
213 if ( rs->sr_type == REP_SEARCH ) {
214 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
215 autogroup_entry_t *age = agg->agg_group;
216 Modification mod;
217 const char *text = NULL;
218 char textbuf[1024];
219 struct berval vals[ 2 ], nvals[ 2 ];
220
221 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
222 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
223
224 vals[ 0 ] = rs->sr_entry->e_name;
225 BER_BVZERO( &vals[ 1 ] );
226 nvals[ 0 ] = rs->sr_entry->e_nname;
227 BER_BVZERO( &nvals[ 1 ] );
228
229 mod.sm_op = LDAP_MOD_ADD;
230 mod.sm_desc = age->age_def->agd_member_ad;
231 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
232 mod.sm_values = vals;
233 mod.sm_nvalues = nvals;
234 mod.sm_numvals = 1;
235
236 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
237 }
238
239 return 0;
240 }
241
242 /*
243 ** Callback used to add entries to a group, which is already in the database.
244 ** (used in on_response)
245 ** The group is passed in autogroup_ga_t->agg_group
246 ** NOTE: Very slow.
247 */
248 static int
249 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
250 {
251 assert( op->o_tag == LDAP_REQ_SEARCH );
252
253 if ( rs->sr_type == REP_SEARCH ) {
254 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
255 autogroup_entry_t *age = agg->agg_group;
256 Modifications *modlist;
257 struct berval vals[ 2 ], nvals[ 2 ];
258
259 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
260 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
261
262 vals[ 0 ] = rs->sr_entry->e_name;
263 BER_BVZERO( &vals[ 1 ] );
264 nvals[ 0 ] = rs->sr_entry->e_nname;
265 BER_BVZERO( &nvals[ 1 ] );
266
267 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
268
269 modlist->sml_op = LDAP_MOD_ADD;
270 modlist->sml_desc = age->age_def->agd_member_ad;
271 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
272
273 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
274 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
275 modlist->sml_numvals = 1;
276
277 modlist->sml_flags = SLAP_MOD_INTERNAL;
278 modlist->sml_next = NULL;
279
280 if ( agg->agg_mod == NULL ) {
281 agg->agg_mod = modlist;
282 agg->agg_mod_last = modlist;
283 } else {
284 agg->agg_mod_last->sml_next = modlist;
285 agg->agg_mod_last = modlist;
286 }
287
288 }
289
290 return 0;
291 }
292
293
294 /*
295 ** Adds all entries matching the passed filter to the specified group.
296 ** If modify == 1, then we modify the group's entry in the database using be_modify.
297 ** If modify == 0, then, we must supply a rw entry for the group,
298 ** because we only modify the entry, without calling be_modify.
299 ** e - the group entry, to which the members will be added
300 ** age - the group
301 ** agf - the filter
302 */
303 static int
304 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
305 {
306 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
307 Operation o = *op;
308 SlapReply rs = { REP_SEARCH };
309 slap_callback cb = { 0 };
310 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
311 autogroup_ga_t agg;
312
313 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
314 age->age_dn.bv_val, 0, 0);
315
316 o.ors_attrsonly = 0;
317 o.o_tag = LDAP_REQ_SEARCH;
318
319 o.o_req_dn = agf->agf_dn;
320 o.o_req_ndn = agf->agf_ndn;
321
322 o.ors_filterstr = agf->agf_filterstr;
323 o.ors_filter = agf->agf_filter;
324
325 o.ors_scope = agf->agf_scope;
326 o.ors_deref = LDAP_DEREF_NEVER;
327 o.ors_limit = NULL;
328 o.ors_tlimit = SLAP_NO_LIMIT;
329 o.ors_slimit = SLAP_NO_LIMIT;
330 o.ors_attrs = slap_anlist_no_attrs;
331
332 agg.agg_group = age;
333 agg.agg_mod = NULL;
334 agg.agg_mod_last = NULL;
335 agg.agg_entry = e;
336 cb.sc_private = &agg;
337
338 if ( modify == 1 ) {
339 cb.sc_response = autogroup_member_search_modify_cb;
340 } else {
341 cb.sc_response = autogroup_member_search_cb;
342 }
343
344 cb.sc_cleanup = NULL;
345 cb.sc_next = NULL;
346
347 o.o_callback = &cb;
348
349 o.o_bd->bd_info = (BackendInfo *)on->on_info;
350 op->o_bd->be_search( &o, &rs );
351 o.o_bd->bd_info = (BackendInfo *)on;
352
353 if ( modify == 1 ) {
354 o = *op;
355 o.o_callback = &null_cb;
356 o.o_tag = LDAP_REQ_MODIFY;
357 o.orm_modlist = agg.agg_mod;
358 o.o_req_dn = age->age_dn;
359 o.o_req_ndn = age->age_ndn;
360 o.o_relax = SLAP_CONTROL_CRITICAL;
361 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
362 o.o_permissive_modify = 1;
363
364 o.o_bd->bd_info = (BackendInfo *)on->on_info;
365 (void)op->o_bd->be_modify( &o, &rs );
366 o.o_bd->bd_info = (BackendInfo *)on;
367
368 slap_mods_free(agg.agg_mod, 1);
369 }
370
371 return 0;
372 }
373
374 /*
375 ** Adds a group to the internal list from the passed entry.
376 ** scan specifies whether to add all maching members to the group.
377 ** modify specifies whether to modify the given group entry (when modify == 0),
378 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
379 ** agi - pointer to the groups and the attribute definitions
380 ** agd - the attribute definition of the added group
381 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
382 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
383 */
384 static int
385 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
386 {
387 autogroup_entry_t **agep = &agi->agi_entry;
388 autogroup_filter_t *agf, *agf_prev = NULL;
389 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
390 LDAPURLDesc *lud = NULL;
391 Attribute *a;
392 BerValue *bv, dn;
393 int rc = 0, match = 1, null_entry = 0;
394
395 if ( e == NULL ) {
396 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
397 LDAP_SUCCESS || e == NULL ) {
398 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
399 return 1;
400 }
401
402 null_entry = 1;
403 }
404
405 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
406 e->e_name.bv_val, 0, 0);
407
408 if ( agi->agi_entry != NULL ) {
409 for ( ; *agep ; agep = &(*agep)->age_next ) {
410 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
411 if ( match == 0 ) {
412 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
413 return 1;
414 }
415 /* goto last */;
416 }
417 }
418
419
420 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
421 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
422 (*agep)->age_def = agd;
423 (*agep)->age_filter = NULL;
424
425 ber_dupbv( &(*agep)->age_dn, &e->e_name );
426 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
427
428 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
429
430 if ( null_entry == 1 ) {
431 a = attrs_dup( a );
432 overlay_entry_release_ov( op, e, 0, on );
433 }
434
435 if( a == NULL ) {
436 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
437 } else {
438 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
439
440 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
441
442 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
443 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
444 /* FIXME: error? */
445 ch_free( agf );
446 continue;
447 }
448
449 agf->agf_scope = lud->lud_scope;
450
451 if ( lud->lud_dn == NULL ) {
452 BER_BVSTR( &dn, "" );
453 } else {
454 ber_str2bv( lud->lud_dn, 0, 0, &dn );
455 }
456
457 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
458 if ( rc != LDAP_SUCCESS ) {
459 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
460 /* FIXME: error? */
461 goto cleanup;
462 }
463
464 if ( lud->lud_filter != NULL ) {
465 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
466 agf->agf_filter = str2filter( lud->lud_filter );
467 }
468
469 agf->agf_next = NULL;
470
471
472 if( (*agep)->age_filter == NULL ) {
473 (*agep)->age_filter = agf;
474 }
475
476 if( agf_prev != NULL ) {
477 agf_prev->agf_next = agf;
478 }
479
480 agf_prev = agf;
481
482 if ( scan == 1 ){
483 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
484 }
485
486 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
487 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
488
489 ldap_free_urldesc( lud );
490
491 continue;
492
493
494 cleanup:;
495
496 ldap_free_urldesc( lud );
497 ch_free( agf );
498 }
499 }
500
501 if ( null_entry == 1 ) {
502 attrs_free( a );
503 }
504 return rc;
505 }
506
507 /*
508 ** Used when opening the database to add all existing
509 ** groups from the database to our internal list.
510 */
511 static int
512 autogroup_group_add_cb( Operation *op, SlapReply *rs )
513 {
514 assert( op->o_tag == LDAP_REQ_SEARCH );
515
516 if ( rs->sr_type == REP_SEARCH ) {
517 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
518
519 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
520 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
521
522 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
523 }
524
525 return 0;
526 }
527
528
529 /*
530 ** When adding a group, we first strip any existing members,
531 ** and add all which match the filters ourselfs.
532 */
533 static int
534 autogroup_add_entry( Operation *op, SlapReply *rs)
535 {
536 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
537 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
538 autogroup_def_t *agd = agi->agi_def;
539 autogroup_entry_t *age = agi->agi_entry;
540 autogroup_filter_t *agf;
541 int rc = 0;
542
543 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
544 op->ora_e->e_name.bv_val, 0, 0);
545
546 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
547
548 /* Check if it's a group. */
549 for ( ; agd ; agd = agd->agd_next ) {
550 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
551 Modification mod;
552 const char *text = NULL;
553 char textbuf[1024];
554
555 mod.sm_op = LDAP_MOD_DELETE;
556 mod.sm_desc = agd->agd_member_ad;
557 mod.sm_type = agd->agd_member_ad->ad_cname;
558 mod.sm_values = NULL;
559 mod.sm_nvalues = NULL;
560
561 /* We don't want any member attributes added by the user. */
562 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
563
564 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
565 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
566 return SLAP_CB_CONTINUE;
567 }
568 }
569
570 for ( ; age ; age = age->age_next ) {
571 ldap_pvt_thread_mutex_lock( &age->age_mutex );
572
573 /* Check if any of the filters are the suffix to the entry DN.
574 If yes, we can test that filter against the entry. */
575
576 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
577 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
578 rc = test_filter( op, op->ora_e, agf->agf_filter );
579 if ( rc == LDAP_COMPARE_TRUE ) {
580 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
581 break;
582 }
583 }
584 }
585 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
586 }
587
588 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
589
590 return SLAP_CB_CONTINUE;
591 }
592
593 /*
594 ** agi - internal group and attribute definitions list
595 ** e - the group to remove from the internal list
596 */
597 static int
598 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
599 {
600 autogroup_entry_t *age = agi->agi_entry,
601 *age_prev = NULL,
602 *age_next;
603 int rc = 1;
604
605 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
606 age->age_dn.bv_val, 0, 0);
607
608 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
609 age_next = age->age_next;
610
611 if ( age == e ) {
612 autogroup_filter_t *agf = age->age_filter,
613 *agf_next;
614
615 if ( age_prev != NULL ) {
616 age_prev->age_next = age_next;
617 } else {
618 agi->agi_entry = NULL;
619 }
620
621 ch_free( age->age_dn.bv_val );
622 ch_free( age->age_ndn.bv_val );
623
624 for( agf_next = agf ; agf_next ; agf = agf_next ){
625 agf_next = agf->agf_next;
626
627 filter_free( agf->agf_filter );
628 ch_free( agf->agf_filterstr.bv_val );
629 ch_free( agf->agf_dn.bv_val );
630 ch_free( agf->agf_ndn.bv_val );
631 }
632
633 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
634 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
635 ch_free( age );
636
637 rc = 0;
638 return rc;
639
640 }
641 }
642
643 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
644
645 return rc;
646
647 }
648
649 static int
650 autogroup_delete_entry( Operation *op, SlapReply *rs)
651 {
652 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
653 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
654 autogroup_entry_t *age = agi->agi_entry,
655 *age_prev, *age_next;
656 autogroup_filter_t *agf;
657 Entry *e;
658 int matched_group = 0, rc = 0;
659
660 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
661
662 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
663
664 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
665 LDAP_SUCCESS || e == NULL ) {
666 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
667 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
668 return SLAP_CB_CONTINUE;
669 }
670
671 /* Check if the entry to be deleted is one of our groups. */
672 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
673 ldap_pvt_thread_mutex_lock( &age->age_mutex );
674 age_next = age->age_next;
675
676 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
677 int match = 1;
678
679 matched_group = 1;
680
681 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
682
683 if ( match == 0 ) {
684 autogroup_delete_group( agi, age );
685 break;
686 }
687 }
688
689 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
690 }
691
692 if ( matched_group == 1 ) {
693 overlay_entry_release_ov( op, e, 0, on );
694 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
695 return SLAP_CB_CONTINUE;
696 }
697
698 /* Check if the entry matches any of the groups.
699 If yes, we can delete the entry from that group. */
700
701 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
702 ldap_pvt_thread_mutex_lock( &age->age_mutex );
703
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, e, agf->agf_filter );
707 if ( rc == LDAP_COMPARE_TRUE ) {
708 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
709 break;
710 }
711 }
712 }
713 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
714 }
715
716 overlay_entry_release_ov( op, e, 0, on );
717 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
718
719 return SLAP_CB_CONTINUE;
720 }
721
722 static int
723 autogroup_response( Operation *op, SlapReply *rs )
724 {
725 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
726 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
727 autogroup_def_t *agd = agi->agi_def;
728 autogroup_entry_t *age = agi->agi_entry;
729 autogroup_filter_t *agf;
730 BerValue new_dn, new_ndn, pdn;
731 Entry *e, *group;
732 Attribute *a;
733 int is_olddn, is_newdn, dn_equal;
734
735 if ( op->o_tag == LDAP_REQ_MODRDN ) {
736 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
737
738 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
739
740 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
741
742 if ( op->oq_modrdn.rs_newSup ) {
743 pdn = *op->oq_modrdn.rs_newSup;
744 } else {
745 dnParent( &op->o_req_dn, &pdn );
746 }
747 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
748
749 if ( op->oq_modrdn.rs_nnewSup ) {
750 pdn = *op->oq_modrdn.rs_nnewSup;
751 } else {
752 dnParent( &op->o_req_ndn, &pdn );
753 }
754 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
755
756 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
757
758 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
759
760 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
761 LDAP_SUCCESS || e == NULL ) {
762 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
763 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
764 return SLAP_CB_CONTINUE;
765 }
766
767 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
768
769
770 if ( a == NULL ) {
771 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
772 overlay_entry_release_ov( op, e, 0, on );
773 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
774 return SLAP_CB_CONTINUE;
775 }
776
777
778 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
779 for ( ; agd; agd = agd->agd_next ) {
780
781 if ( value_find_ex( slap_schema.si_ad_objectClass,
782 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
783 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
784 a->a_nvals, &agd->agd_oc->soc_cname,
785 op->o_tmpmemctx ) == 0 )
786 {
787 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
788 int match = 1;
789
790 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
791 if ( match == 0 ) {
792 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
793 ber_dupbv( &age->age_dn, &new_dn );
794 ber_dupbv( &age->age_ndn, &new_ndn );
795
796 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
797 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
798 overlay_entry_release_ov( op, e, 0, on );
799 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
800 return SLAP_CB_CONTINUE;
801 }
802 }
803
804 }
805 }
806
807 overlay_entry_release_ov( op, e, 0, on );
808
809 /* For each group:
810 1. check if the orginal entry's DN is in the group.
811 2. chceck if the any of the group filter's base DN is a suffix of the new DN
812
813 If 1 and 2 are both false, we do nothing.
814 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
815 If 1 is false, and 2 is true, we check the entry against the group's filters,
816 and add it's DN to the group.
817 If 1 is true, and 2 is false, we delete the entry's DN from the group.
818 */
819 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
820 is_olddn = 0;
821 is_newdn = 0;
822
823
824 ldap_pvt_thread_mutex_lock( &age->age_mutex );
825
826 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
827 LDAP_SUCCESS || group == NULL ) {
828 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
829
830 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
831 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
832
833 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
834 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
835 return SLAP_CB_CONTINUE;
836 }
837
838 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
839
840 if ( a != NULL ) {
841 if ( value_find_ex( age->age_def->agd_member_ad,
842 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
843 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
844 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
845 {
846 is_olddn = 1;
847 }
848
849 }
850
851 overlay_entry_release_ov( op, group, 0, on );
852
853 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
854 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
855 is_newdn = 1;
856 break;
857 }
858 }
859
860
861 if ( is_olddn == 1 && is_newdn == 0 ) {
862 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
863 } else
864 if ( is_olddn == 0 && is_newdn == 1 ) {
865 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
866 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
867 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
868 break;
869 }
870 }
871 } else
872 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
873 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
874 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
875 }
876
877 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
878 }
879
880 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
881 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
882
883 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
884 }
885 }
886
887 if ( op->o_tag == LDAP_REQ_MODIFY ) {
888 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
889 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
890
891 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
892
893 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
894 LDAP_SUCCESS || e == NULL ) {
895 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
896 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
897 return SLAP_CB_CONTINUE;
898 }
899
900 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
901
902
903 if ( a == NULL ) {
904 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
905 overlay_entry_release_ov( op, e, 0, on );
906 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
907 return SLAP_CB_CONTINUE;
908 }
909
910
911 /* If we modify a group's memberURL, we have to delete all of it's members,
912 and add them anew, because we cannot tell from which memberURL a member was added. */
913 for ( ; agd; agd = agd->agd_next ) {
914
915 if ( value_find_ex( slap_schema.si_ad_objectClass,
916 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
917 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
918 a->a_nvals, &agd->agd_oc->soc_cname,
919 op->o_tmpmemctx ) == 0 )
920 {
921 Modifications *m;
922 int match = 1;
923
924 m = op->orm_modlist;
925
926 for ( ; age ; age = age->age_next ) {
927 ldap_pvt_thread_mutex_lock( &age->age_mutex );
928
929 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
930
931 if ( match == 0 ) {
932 for ( ; m ; m = m->sml_next ) {
933 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
934 autogroup_def_t *group_agd = age->age_def;
935 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
936 op->o_req_dn.bv_val, 0, 0);
937
938 overlay_entry_release_ov( op, e, 0, on );
939
940 autogroup_delete_member_from_group( op, NULL, NULL, age );
941 autogroup_delete_group( agi, age );
942
943 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
944
945 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
946 return SLAP_CB_CONTINUE;
947 }
948 }
949
950 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
951 break;
952 }
953
954 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
955 }
956
957 overlay_entry_release_ov( op, e, 0, on );
958 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
959 return SLAP_CB_CONTINUE;
960 }
961 }
962
963 overlay_entry_release_ov( op, e, 0, on );
964
965 /* When modifing any of the attributes of an entry, we must
966 check if the entry is in any of our groups, and if
967 the modified entry maches any of the filters of that group.
968
969 If the entry exists in a group, but the modified attributes do
970 not match any of the group's filters, we delete the entry from that group.
971 If the entry doesn't exist in a group, but matches a filter,
972 we add it to that group.
973 */
974 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
975 is_olddn = 0;
976 is_newdn = 0;
977
978
979 ldap_pvt_thread_mutex_lock( &age->age_mutex );
980
981 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
982 LDAP_SUCCESS || group == NULL ) {
983 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
984 age->age_dn.bv_val, 0, 0);
985
986 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
987 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
988 return SLAP_CB_CONTINUE;
989 }
990
991 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
992
993 if ( a != NULL ) {
994 if ( value_find_ex( age->age_def->agd_member_ad,
995 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
996 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
997 a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
998 {
999 is_olddn = 1;
1000 }
1001
1002 }
1003
1004 overlay_entry_release_ov( op, group, 0, on );
1005
1006 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1007 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1008 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1009 is_newdn = 1;
1010 break;
1011 }
1012 }
1013 }
1014
1015 if ( is_olddn == 1 && is_newdn == 0 ) {
1016 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1017 } else
1018 if ( is_olddn == 0 && is_newdn == 1 ) {
1019 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1020 }
1021
1022 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1023 }
1024
1025 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1026 }
1027 }
1028
1029 return SLAP_CB_CONTINUE;
1030 }
1031
1032 /*
1033 ** When modifing a group, we must deny any modifications to the member attribute,
1034 ** because the group would be inconsistent.
1035 */
1036 static int
1037 autogroup_modify_entry( Operation *op, SlapReply *rs)
1038 {
1039 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1040 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1041 autogroup_def_t *agd = agi->agi_def;
1042 autogroup_entry_t *age = agi->agi_entry;
1043 Entry *e;
1044 Attribute *a;
1045
1046 if ( get_manageDSAit( op ) ) {
1047 return SLAP_CB_CONTINUE;
1048 }
1049
1050 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1051 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1052
1053 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1054 LDAP_SUCCESS || e == NULL ) {
1055 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1056 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1057 return SLAP_CB_CONTINUE;
1058 }
1059
1060 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1061
1062 if ( a == NULL ) {
1063 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1064 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1065 return SLAP_CB_CONTINUE;
1066 }
1067
1068
1069 for ( ; agd; agd = agd->agd_next ) {
1070
1071 if ( value_find_ex( slap_schema.si_ad_objectClass,
1072 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1073 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1074 a->a_nvals, &agd->agd_oc->soc_cname,
1075 op->o_tmpmemctx ) == 0 )
1076 {
1077 Modifications *m;
1078 int match = 1;
1079
1080 m = op->orm_modlist;
1081
1082 for ( ; age ; age = age->age_next ) {
1083 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1084
1085 if ( match == 0 ) {
1086 for ( ; m ; m = m->sml_next ) {
1087 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1088 overlay_entry_release_ov( op, e, 0, on );
1089 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1090 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1091 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1092 return LDAP_CONSTRAINT_VIOLATION;
1093 }
1094 }
1095 break;
1096 }
1097 }
1098
1099 overlay_entry_release_ov( op, e, 0, on );
1100 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1101 return SLAP_CB_CONTINUE;
1102 }
1103 }
1104
1105 overlay_entry_release_ov( op, e, 0, on );
1106 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1107 return SLAP_CB_CONTINUE;
1108 }
1109
1110 /*
1111 ** Builds a filter for searching for the
1112 ** group entries, according to the objectClass.
1113 */
1114 static int
1115 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1116 {
1117 char *ptr;
1118
1119 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1120
1121 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1122 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1123 + agd->agd_oc->soc_cname.bv_len;
1124 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1125 *ptr++ = '(';
1126 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1127 *ptr++ = '=';
1128 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1129 *ptr++ = ')';
1130 *ptr = '\0';
1131
1132 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1133
1134 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1135
1136 return 0;
1137 }
1138
1139 enum {
1140 AG_ATTRSET = 1,
1141 AG_LAST
1142 };
1143
1144 static ConfigDriver ag_cfgen;
1145
1146 static ConfigTable agcfg[] = {
1147 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1148 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1149 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1150 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1151 "EQUALITY caseIgnoreMatch "
1152 "SYNTAX OMsDirectoryString "
1153 "X-ORDERED 'VALUES' )",
1154 NULL, NULL },
1155 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1156 };
1157
1158 static ConfigOCs agocs[] = {
1159 { "( OLcfgCtOc:2.1 "
1160 "NAME 'olcAutomaticGroups' "
1161 "DESC 'Automatic groups configuration' "
1162 "SUP olcOverlayConfig "
1163 "MAY olcAGattrSet )",
1164 Cft_Overlay, agcfg, NULL, NULL },
1165 { NULL, 0, NULL }
1166 };
1167
1168
1169 static int
1170 ag_cfgen( ConfigArgs *c )
1171 {
1172 slap_overinst *on = (slap_overinst *)c->bi;
1173 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1174 autogroup_def_t *agd;
1175 autogroup_entry_t *age;
1176
1177 int rc = 0, i;
1178
1179 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1180
1181 if( agi == NULL ) {
1182 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1183 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1184 agi->agi_def = NULL;
1185 agi->agi_entry = NULL;
1186 on->on_bi.bi_private = (void *)agi;
1187 }
1188
1189 agd = agi->agi_def;
1190 age = agi->agi_entry;
1191
1192 if ( c->op == SLAP_CONFIG_EMIT ) {
1193
1194 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1195
1196 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1197 struct berval bv;
1198 char *ptr = c->cr_msg;
1199
1200 assert(agd->agd_oc != NULL);
1201 assert(agd->agd_member_url_ad != NULL);
1202 assert(agd->agd_member_ad != NULL);
1203
1204 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1205 SLAP_X_ORDERED_FMT "%s %s %s", i,
1206 agd->agd_oc->soc_cname.bv_val,
1207 agd->agd_member_url_ad->ad_cname.bv_val,
1208 agd->agd_member_ad->ad_cname.bv_val );
1209
1210 bv.bv_val = c->cr_msg;
1211 bv.bv_len = ptr - bv.bv_val;
1212 value_add_one ( &c->rvalue_vals, &bv );
1213
1214 }
1215 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1216
1217 return rc;
1218
1219 }else if ( c->op == LDAP_MOD_DELETE ) {
1220 if ( c->valx < 0) {
1221 autogroup_def_t *agd_next;
1222 autogroup_entry_t *age_next;
1223 autogroup_filter_t *agf = age->age_filter,
1224 *agf_next;
1225
1226 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1227
1228 for ( agd_next = agd; agd_next; agd = agd_next ) {
1229 agd_next = agd->agd_next;
1230
1231 ch_free( agd );
1232 }
1233
1234 for ( age_next = age ; age_next ; age = age_next ) {
1235 age_next = age->age_next;
1236
1237 ch_free( age->age_dn.bv_val );
1238 ch_free( age->age_ndn.bv_val );
1239
1240 for( agf_next = agf ; agf_next ; agf = agf_next ){
1241 agf_next = agf->agf_next;
1242
1243 filter_free( agf->agf_filter );
1244 ch_free( agf->agf_filterstr.bv_val );
1245 ch_free( agf->agf_dn.bv_val );
1246 ch_free( agf->agf_ndn.bv_val );
1247 }
1248
1249 ldap_pvt_thread_mutex_init( &age->age_mutex );
1250 ch_free( age );
1251 }
1252
1253 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1254
1255 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1256 ch_free( agi );
1257 on->on_bi.bi_private = NULL;
1258
1259 } else {
1260 autogroup_def_t **agdp;
1261 autogroup_entry_t *age_next, *age_prev;
1262 autogroup_filter_t *agf,
1263 *agf_next;
1264
1265 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1266
1267 for ( i = 0, agdp = &agi->agi_def;
1268 i < c->valx; i++ )
1269 {
1270 if ( *agdp == NULL) {
1271 return 1;
1272 }
1273 agdp = &(*agdp)->agd_next;
1274 }
1275
1276 agd = *agdp;
1277 *agdp = agd->agd_next;
1278
1279 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1280 age_next = age->age_next;
1281
1282 if( age->age_def == agd ) {
1283 agf = age->age_filter;
1284
1285 ch_free( age->age_dn.bv_val );
1286 ch_free( age->age_ndn.bv_val );
1287
1288 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1289 agf_next = agf->agf_next;
1290 filter_free( agf->agf_filter );
1291 ch_free( agf->agf_filterstr.bv_val );
1292 ch_free( agf->agf_dn.bv_val );
1293 ch_free( agf->agf_ndn.bv_val );
1294 }
1295
1296 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1297 ch_free( age );
1298
1299 age = age_prev;
1300
1301 if( age_prev != NULL ) {
1302 age_prev->age_next = age_next;
1303 }
1304 }
1305 }
1306
1307 ch_free( agd );
1308 agd = agi->agi_def;
1309 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1310
1311 }
1312
1313 return rc;
1314 }
1315
1316 switch(c->type){
1317 case AG_ATTRSET: {
1318 autogroup_def_t **agdp,
1319 *agd_next = NULL;
1320 ObjectClass *oc = NULL;
1321 AttributeDescription *member_url_ad = NULL,
1322 *member_ad = NULL;
1323 const char *text;
1324
1325
1326 oc = oc_find( c->argv[ 1 ] );
1327 if( oc == NULL ){
1328 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1329 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1330 "unable to find ObjectClass \"%s\"",
1331 c->argv[ 1 ] );
1332 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1333 c->log, c->cr_msg, 0 );
1334 return 1;
1335 }
1336
1337
1338 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1339 if( rc != LDAP_SUCCESS ) {
1340 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1341 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1342 "unable to find AttributeDescription \"%s\"",
1343 c->argv[ 2 ] );
1344 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1345 c->log, c->cr_msg, 0 );
1346 return 1;
1347 }
1348
1349 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1350 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1351 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1352 "AttributeDescription \"%s\" ",
1353 "must be of a subtype \"labeledURI\"",
1354 c->argv[ 2 ] );
1355 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1356 c->log, c->cr_msg, 0 );
1357 return 1;
1358 }
1359
1360 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1361 if( rc != LDAP_SUCCESS ) {
1362 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1363 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1364 "unable to find AttributeDescription \"%s\"",
1365 c->argv[ 3 ] );
1366 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1367 c->log, c->cr_msg, 0 );
1368 return 1;
1369 }
1370
1371 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1372
1373 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1374 /* The same URL attribute / member attribute pair
1375 * cannot be repeated */
1376
1377 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1378 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1379 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1380 "URL attributeDescription \"%s\" already mapped",
1381 member_ad->ad_cname.bv_val );
1382 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1383 c->log, c->cr_msg, 0 );
1384 /* return 1; //warning*/
1385 }
1386 }
1387
1388 if ( c->valx > 0 ) {
1389 int i;
1390
1391 for ( i = 0, agdp = &agi->agi_def ;
1392 i < c->valx; i++ )
1393 {
1394 if ( *agdp == NULL ) {
1395 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1396 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1397 "invalid index {%d}",
1398 c->valx );
1399 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1400 c->log, c->cr_msg, 0 );
1401
1402 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1403 return 1;
1404 }
1405 agdp = &(*agdp)->agd_next;
1406 }
1407 agd_next = *agdp;
1408
1409 } else {
1410 for ( agdp = &agi->agi_def; *agdp;
1411 agdp = &(*agdp)->agd_next )
1412 /* goto last */;
1413 }
1414
1415 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1416
1417 (*agdp)->agd_oc = oc;
1418 (*agdp)->agd_member_url_ad = member_url_ad;
1419 (*agdp)->agd_member_ad = member_ad;
1420 (*agdp)->agd_next = agd_next;
1421
1422 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1423
1424 } break;
1425
1426 default:
1427 rc = 1;
1428 break;
1429 }
1430
1431 return rc;
1432 }
1433
1434 /*
1435 ** Do a search for all the groups in the
1436 ** database, and add them to out internal list.
1437 */
1438 static int
1439 autogroup_db_open(
1440 BackendDB *be,
1441 ConfigReply *cr )
1442 {
1443 slap_overinst *on = (slap_overinst *) be->bd_info;
1444 autogroup_info_t *agi = on->on_bi.bi_private;
1445 autogroup_def_t *agd;
1446 autogroup_sc_t ags;
1447 Operation *op;
1448 SlapReply rs = { REP_RESULT };
1449 slap_callback cb = { 0 };
1450
1451 void *thrctx = ldap_pvt_thread_pool_context();
1452 Connection conn = { 0 };
1453 OperationBuffer opbuf;
1454
1455 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1456
1457 if ( agi == NULL ) {
1458 return 0;
1459 }
1460
1461 connection_fake_init( &conn, &opbuf, thrctx );
1462 op = &opbuf.ob_op;
1463
1464 op->ors_attrsonly = 0;
1465 op->o_tag = LDAP_REQ_SEARCH;
1466 op->o_dn = be->be_rootdn;
1467 op->o_ndn = be->be_rootndn;
1468
1469 op->o_req_dn = be->be_suffix[0];
1470 op->o_req_ndn = be->be_nsuffix[0];
1471
1472 op->ors_scope = LDAP_SCOPE_SUBTREE;
1473 op->ors_deref = LDAP_DEREF_NEVER;
1474 op->ors_limit = NULL;
1475 op->ors_tlimit = SLAP_NO_LIMIT;
1476 op->ors_slimit = SLAP_NO_LIMIT;
1477 op->ors_attrs = slap_anlist_no_attrs;
1478
1479 op->o_bd = be;
1480 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1481
1482 ags.ags_info = agi;
1483 cb.sc_private = &ags;
1484 cb.sc_response = autogroup_group_add_cb;
1485 cb.sc_cleanup = NULL;
1486 cb.sc_next = NULL;
1487
1488 op->o_callback = &cb;
1489
1490 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1491
1492 autogroup_build_def_filter(agd, op);
1493
1494 ags.ags_def = agd;
1495
1496 op->o_bd->be_search( op, &rs );
1497
1498 filter_free_x( op, op->ors_filter, 1 );
1499 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1500 }
1501
1502 return 0;
1503 }
1504
1505 static int
1506 autogroup_db_close(
1507 BackendDB *be,
1508 ConfigReply *cr )
1509 {
1510 slap_overinst *on = (slap_overinst *) be->bd_info;
1511
1512 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1513
1514 if ( on->on_bi.bi_private ) {
1515 autogroup_info_t *agi = on->on_bi.bi_private;
1516 autogroup_entry_t *age = agi->agi_entry,
1517 *age_next;
1518 autogroup_filter_t *agf, *agf_next;
1519
1520 for ( age_next = age; age_next; age = age_next ) {
1521 age_next = age->age_next;
1522
1523 ch_free( age->age_dn.bv_val );
1524 ch_free( age->age_ndn.bv_val );
1525
1526 agf = age->age_filter;
1527
1528 for ( agf_next = agf; agf_next; agf = agf_next ) {
1529 agf_next = agf->agf_next;
1530
1531 filter_free( agf->agf_filter );
1532 ch_free( agf->agf_filterstr.bv_val );
1533 ch_free( agf->agf_dn.bv_val );
1534 ch_free( agf->agf_ndn.bv_val );
1535 ch_free( agf );
1536 }
1537
1538 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1539 ch_free( age );
1540 }
1541 }
1542
1543 return 0;
1544 }
1545
1546 static int
1547 autogroup_db_destroy(
1548 BackendDB *be,
1549 ConfigReply *cr )
1550 {
1551 slap_overinst *on = (slap_overinst *) be->bd_info;
1552
1553 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
1554
1555 if ( on->on_bi.bi_private ) {
1556 autogroup_info_t *agi = on->on_bi.bi_private;
1557 autogroup_def_t *agd = agi->agi_def,
1558 *agd_next;
1559
1560 for ( agd_next = agd; agd_next; agd = agd_next ) {
1561 agd_next = agd->agd_next;
1562
1563 ch_free( agd );
1564 }
1565
1566 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
1567 ch_free( agi );
1568 }
1569
1570 return 0;
1571 }
1572
1573 static slap_overinst autogroup = { { NULL } };
1574
1575 static
1576 int
1577 autogroup_initialize(void)
1578 {
1579 int rc = 0;
1580 autogroup.on_bi.bi_type = "autogroup";
1581
1582 autogroup.on_bi.bi_db_open = autogroup_db_open;
1583 autogroup.on_bi.bi_db_close = autogroup_db_close;
1584 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
1585
1586 autogroup.on_bi.bi_op_add = autogroup_add_entry;
1587 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
1588 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
1589
1590 autogroup.on_response = autogroup_response;
1591
1592 autogroup.on_bi.bi_cf_ocs = agocs;
1593
1594 rc = config_register_schema( agcfg, agocs );
1595 if ( rc ) {
1596 return rc;
1597 }
1598
1599 return overlay_register( &autogroup );
1600 }
1601
1602 int
1603 init_module( int argc, char *argv[] )
1604 {
1605 return autogroup_initialize();
1606 }
1607