autogroup.c revision 1.1.1.3.12.1 1 /* $NetBSD: autogroup.c,v 1.1.1.3.12.1 2014/08/19 23:51:56 tls Exp $ */
2
3 /* autogroup.c - automatic group overlay */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2007-2014 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 * Raphael Ouazana
25 * Norbert Pueschel
26 * Christian Manal
27 */
28
29 #include "portable.h"
30
31 #include <stdio.h>
32
33 #include <ac/string.h>
34
35 #include "slap.h"
36 #include "config.h"
37 #include "lutil.h"
38
39 #ifndef SLAPD_MEMBEROF_ATTR
40 #define SLAPD_MEMBEROF_ATTR "memberOf"
41 #endif
42
43 /* Filter represents the memberURL of a group. */
44 typedef struct autogroup_filter_t {
45 struct berval agf_dn; /* The base DN in memberURL */
46 struct berval agf_ndn;
47 struct berval agf_filterstr;
48 Filter *agf_filter;
49 int agf_scope;
50 AttributeName *agf_anlist;
51 struct autogroup_filter_t *agf_next;
52 } autogroup_filter_t;
53
54 /* Description of group attributes. */
55 typedef struct autogroup_def_t {
56 ObjectClass *agd_oc;
57 AttributeDescription *agd_member_url_ad;
58 AttributeDescription *agd_member_ad;
59 struct autogroup_def_t *agd_next;
60 } autogroup_def_t;
61
62 /* Represents the group entry. */
63 typedef struct autogroup_entry_t {
64 BerValue age_dn;
65 BerValue age_ndn;
66 autogroup_filter_t *age_filter; /* List of filters made from memberURLs */
67 autogroup_def_t *age_def; /* Attribute definition */
68 ldap_pvt_thread_mutex_t age_mutex;
69 int age_mustrefresh; /* Defined in request to refresh in response */
70 int age_modrdn_olddnmodified; /* Defined in request to refresh in response */
71 struct autogroup_entry_t *age_next;
72 } autogroup_entry_t;
73
74 /* Holds pointers to attribute definitions and groups. */
75 typedef struct autogroup_info_t {
76 autogroup_def_t *agi_def; /* Group attributes definitions. */
77 autogroup_entry_t *agi_entry; /* Group entries. */
78 AttributeDescription *agi_memberof_ad; /* memberOf attribute description */
79 ldap_pvt_thread_mutex_t agi_mutex;
80 } autogroup_info_t;
81
82 /* Search callback for adding groups initially. */
83 typedef struct autogroup_sc_t {
84 autogroup_info_t *ags_info; /* Group definitions and entries. */
85 autogroup_def_t *ags_def; /* Attributes definition of the group being added. */
86 } autogroup_sc_t;
87
88 /* Used for adding members, found when searching, to a group. */
89 typedef struct autogroup_ga_t {
90 autogroup_entry_t *agg_group; /* The group to which the members will be added. */
91 autogroup_filter_t *agg_filter; /* Current filter */
92 Entry *agg_entry; /* Used in autogroup_member_search_cb to modify
93 this entry with the search results. */
94
95 Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
96 search results which will be added to the group. */
97
98 Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
99 have to search for the last mod added. */
100 } autogroup_ga_t;
101
102
103 /*
104 ** dn, ndn - the DN of the member to add
105 ** age - the group to which the member DN will be added
106 */
107 static int
108 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
109 {
110 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
111 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
112 SlapReply sreply = {REP_RESULT};
113 BerValue *vals, *nvals;
114 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
115 Operation o = *op;
116
117 assert( dn != NULL );
118 assert( ndn != NULL );
119 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
120 dn->bv_val, age->age_dn.bv_val, 0);
121
122 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
123 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
124 ber_dupbv( vals, dn );
125 BER_BVZERO( &vals[ 1 ] );
126 ber_dupbv( nvals, ndn );
127 BER_BVZERO( &nvals[ 1 ] );
128
129 modlist->sml_op = LDAP_MOD_ADD;
130 modlist->sml_desc = age->age_def->agd_member_ad;
131 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
132 modlist->sml_values = vals;
133 modlist->sml_nvalues = nvals;
134 modlist->sml_numvals = 1;
135 modlist->sml_flags = SLAP_MOD_INTERNAL;
136 modlist->sml_next = NULL;
137
138 o.o_tag = LDAP_REQ_MODIFY;
139 o.o_callback = &cb;
140 o.orm_modlist = modlist;
141 o.o_req_dn = age->age_dn;
142 o.o_req_ndn = age->age_ndn;
143 o.o_permissive_modify = 1;
144 o.o_managedsait = SLAP_CONTROL_CRITICAL;
145 o.o_relax = SLAP_CONTROL_CRITICAL;
146
147 o.o_bd->bd_info = (BackendInfo *)on->on_info;
148 (void)op->o_bd->be_modify( &o, &sreply );
149 o.o_bd->bd_info = (BackendInfo *)on;
150
151 slap_mods_free( modlist, 1 );
152
153 return sreply.sr_err;
154 }
155
156 /*
157 ** e - the entry where to get the attribute values
158 ** age - the group to which the values will be added
159 */
160 static int
161 autogroup_add_member_values_to_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc )
162 {
163 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
164 Modifications modlist;
165 SlapReply sreply = {REP_RESULT};
166 Attribute *attr;
167 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
168 Operation o = *op;
169
170 assert( e != NULL );
171 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
172 e->e_name.bv_val, age->age_dn.bv_val, 0);
173
174 attr = attrs_find( e->e_attrs, attrdesc );
175 if (!attr) {
176 // Nothing to add
177 return LDAP_SUCCESS;
178 }
179
180 modlist.sml_op = LDAP_MOD_ADD;
181 modlist.sml_desc = age->age_def->agd_member_ad;
182 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
183 modlist.sml_values = attr->a_vals;
184 modlist.sml_nvalues = attr->a_nvals;
185 modlist.sml_numvals = attr->a_numvals;
186 modlist.sml_flags = SLAP_MOD_INTERNAL;
187 modlist.sml_next = NULL;
188
189 o.o_tag = LDAP_REQ_MODIFY;
190 o.o_callback = &cb;
191 o.orm_modlist = &modlist;
192 o.o_req_dn = age->age_dn;
193 o.o_req_ndn = age->age_ndn;
194 o.o_permissive_modify = 1;
195 o.o_managedsait = SLAP_CONTROL_CRITICAL;
196 o.o_relax = SLAP_CONTROL_CRITICAL;
197
198 o.o_bd->bd_info = (BackendInfo *)on->on_info;
199 (void)op->o_bd->be_modify( &o, &sreply );
200 o.o_bd->bd_info = (BackendInfo *)on;
201
202 return sreply.sr_err;
203 }
204
205 /*
206 ** dn,ndn - the DN to be deleted
207 ** age - the group from which the DN will be deleted
208 ** If we pass a NULL dn and ndn, all members are deleted from the group.
209 */
210 static int
211 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
212 {
213 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
214 Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
215 SlapReply sreply = {REP_RESULT};
216 BerValue *vals, *nvals;
217 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
218 Operation o = *op;
219
220 if ( dn == NULL || ndn == NULL ) {
221 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
222 age->age_dn.bv_val, 0 ,0);
223
224 modlist->sml_values = NULL;
225 modlist->sml_nvalues = NULL;
226 modlist->sml_numvals = 0;
227 } else {
228 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
229 dn->bv_val, age->age_dn.bv_val, 0);
230
231 vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
232 nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
233 ber_dupbv( vals, dn );
234 BER_BVZERO( &vals[ 1 ] );
235 ber_dupbv( nvals, ndn );
236 BER_BVZERO( &nvals[ 1 ] );
237
238 modlist->sml_values = vals;
239 modlist->sml_nvalues = nvals;
240 modlist->sml_numvals = 1;
241 }
242
243
244 modlist->sml_op = LDAP_MOD_DELETE;
245 modlist->sml_desc = age->age_def->agd_member_ad;
246 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
247 modlist->sml_flags = SLAP_MOD_INTERNAL;
248 modlist->sml_next = NULL;
249
250 o.o_callback = &cb;
251 o.o_tag = LDAP_REQ_MODIFY;
252 o.orm_modlist = modlist;
253 o.o_req_dn = age->age_dn;
254 o.o_req_ndn = age->age_ndn;
255 o.o_relax = SLAP_CONTROL_CRITICAL;
256 o.o_managedsait = SLAP_CONTROL_CRITICAL;
257 o.o_permissive_modify = 1;
258
259 o.o_bd->bd_info = (BackendInfo *)on->on_info;
260 (void)op->o_bd->be_modify( &o, &sreply );
261 o.o_bd->bd_info = (BackendInfo *)on;
262
263 slap_mods_free( modlist, 1 );
264
265 return sreply.sr_err;
266 }
267
268 /*
269 ** e - the entry where to get the attribute values
270 ** age - the group from which the values will be deleted
271 */
272 static int
273 autogroup_delete_member_values_from_group( Operation *op, Entry *e, autogroup_entry_t *age, AttributeDescription *attrdesc )
274 {
275 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
276 Modifications modlist;
277 SlapReply sreply = {REP_RESULT};
278 Attribute *attr;
279 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
280 Operation o = *op;
281
282 assert( e != NULL );
283 Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n",
284 e->e_name.bv_val, age->age_dn.bv_val, 0);
285
286 attr = attrs_find( e->e_attrs, attrdesc );
287 if (!attr) {
288 // Nothing to add
289 return LDAP_SUCCESS;
290 }
291
292 modlist.sml_op = LDAP_MOD_DELETE;
293 modlist.sml_desc = age->age_def->agd_member_ad;
294 modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
295 modlist.sml_values = attr->a_vals;
296 modlist.sml_nvalues = attr->a_nvals;
297 modlist.sml_numvals = attr->a_numvals;
298 modlist.sml_flags = SLAP_MOD_INTERNAL;
299 modlist.sml_next = NULL;
300
301 o.o_tag = LDAP_REQ_MODIFY;
302 o.o_callback = &cb;
303 o.orm_modlist = &modlist;
304 o.o_req_dn = age->age_dn;
305 o.o_req_ndn = age->age_ndn;
306 o.o_permissive_modify = 1;
307 o.o_managedsait = SLAP_CONTROL_CRITICAL;
308 o.o_relax = SLAP_CONTROL_CRITICAL;
309
310 o.o_bd->bd_info = (BackendInfo *)on->on_info;
311 (void)op->o_bd->be_modify( &o, &sreply );
312 o.o_bd->bd_info = (BackendInfo *)on;
313
314 return sreply.sr_err;
315 }
316
317 /*
318 ** Callback used to add entries to a group,
319 ** which are going to be written in the database
320 ** (used in bi_op_add)
321 ** The group is passed in autogroup_ga_t->agg_group
322 */
323 static int
324 autogroup_member_search_cb( Operation *op, SlapReply *rs )
325 {
326 assert( op->o_tag == LDAP_REQ_SEARCH );
327
328 if ( rs->sr_type == REP_SEARCH ) {
329 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
330 autogroup_entry_t *age = agg->agg_group;
331 autogroup_filter_t *agf = agg->agg_filter;
332 Modification mod;
333 const char *text = NULL;
334 char textbuf[1024];
335 struct berval *vals, *nvals;
336 struct berval lvals[ 2 ], lnvals[ 2 ];
337 int numvals;
338
339 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
340 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
341
342 if ( agf->agf_anlist ) {
343 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
344 if (attr) {
345 vals = attr->a_vals;
346 nvals = attr->a_nvals;
347 numvals = attr->a_numvals;
348 } else {
349 // Nothing to add
350 return 0;
351 }
352 } else {
353 lvals[ 0 ] = rs->sr_entry->e_name;
354 BER_BVZERO( &lvals[ 1 ] );
355 lnvals[ 0 ] = rs->sr_entry->e_nname;
356 BER_BVZERO( &lnvals[ 1 ] );
357 vals = lvals;
358 nvals = lnvals;
359 numvals = 1;
360 }
361
362 mod.sm_op = LDAP_MOD_ADD;
363 mod.sm_desc = age->age_def->agd_member_ad;
364 mod.sm_type = age->age_def->agd_member_ad->ad_cname;
365 mod.sm_values = vals;
366 mod.sm_nvalues = nvals;
367 mod.sm_numvals = numvals;
368
369 modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
370 }
371
372 return 0;
373 }
374
375 /*
376 ** Callback used to add entries to a group, which is already in the database.
377 ** (used in on_response)
378 ** The group is passed in autogroup_ga_t->agg_group
379 ** NOTE: Very slow.
380 */
381 static int
382 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
383 {
384 assert( op->o_tag == LDAP_REQ_SEARCH );
385
386 if ( rs->sr_type == REP_SEARCH ) {
387 autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private;
388 autogroup_entry_t *age = agg->agg_group;
389 autogroup_filter_t *agf = agg->agg_filter;
390 Modifications *modlist;
391 struct berval *vals, *nvals;
392 struct berval lvals[ 2 ], lnvals[ 2 ];
393 int numvals;
394
395 Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
396 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
397
398 if ( agf->agf_anlist ) {
399 Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
400 if (attr) {
401 vals = attr->a_vals;
402 nvals = attr->a_nvals;
403 numvals = attr->a_numvals;
404 } else {
405 // Nothing to add
406 return 0;
407 }
408 } else {
409 lvals[ 0 ] = rs->sr_entry->e_name;
410 BER_BVZERO( &lvals[ 1 ] );
411 lnvals[ 0 ] = rs->sr_entry->e_nname;
412 BER_BVZERO( &lnvals[ 1 ] );
413 vals = lvals;
414 nvals = lnvals;
415 numvals = 1;
416 }
417
418 if ( numvals ) {
419 modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
420
421 modlist->sml_op = LDAP_MOD_ADD;
422 modlist->sml_desc = age->age_def->agd_member_ad;
423 modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
424
425 ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
426 ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
427 modlist->sml_numvals = numvals;
428
429 modlist->sml_flags = SLAP_MOD_INTERNAL;
430 modlist->sml_next = NULL;
431
432 if ( agg->agg_mod == NULL ) {
433 agg->agg_mod = modlist;
434 agg->agg_mod_last = modlist;
435 } else {
436 agg->agg_mod_last->sml_next = modlist;
437 agg->agg_mod_last = modlist;
438 }
439 }
440
441 }
442
443 return 0;
444 }
445
446
447 /*
448 ** Adds all entries matching the passed filter to the specified group.
449 ** If modify == 1, then we modify the group's entry in the database using be_modify.
450 ** If modify == 0, then, we must supply a rw entry for the group,
451 ** because we only modify the entry, without calling be_modify.
452 ** e - the group entry, to which the members will be added
453 ** age - the group
454 ** agf - the filter
455 */
456 static int
457 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
458 {
459 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
460 Operation o = *op;
461 SlapReply rs = { REP_SEARCH };
462 slap_callback cb = { 0 };
463 slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL };
464 autogroup_ga_t agg;
465
466 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
467 age->age_dn.bv_val, 0, 0);
468
469 o.ors_attrsonly = 0;
470 o.o_tag = LDAP_REQ_SEARCH;
471
472 o.o_req_dn = agf->agf_dn;
473 o.o_req_ndn = agf->agf_ndn;
474
475 o.ors_filterstr = agf->agf_filterstr;
476 o.ors_filter = agf->agf_filter;
477
478 o.ors_scope = agf->agf_scope;
479 o.ors_deref = LDAP_DEREF_NEVER;
480 o.ors_limit = NULL;
481 o.ors_tlimit = SLAP_NO_LIMIT;
482 o.ors_slimit = SLAP_NO_LIMIT;
483 o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
484
485 agg.agg_group = age;
486 agg.agg_filter = agf;
487 agg.agg_mod = NULL;
488 agg.agg_mod_last = NULL;
489 agg.agg_entry = e;
490 cb.sc_private = &agg;
491
492 if ( modify == 1 ) {
493 cb.sc_response = autogroup_member_search_modify_cb;
494 } else {
495 cb.sc_response = autogroup_member_search_cb;
496 }
497
498 cb.sc_cleanup = NULL;
499 cb.sc_next = NULL;
500
501 o.o_callback = &cb;
502
503 o.o_bd->bd_info = (BackendInfo *)on->on_info;
504 op->o_bd->be_search( &o, &rs );
505 o.o_bd->bd_info = (BackendInfo *)on;
506
507 if ( modify == 1 && agg.agg_mod ) {
508 rs_reinit( &rs, REP_RESULT );
509
510 o = *op;
511 o.o_callback = &null_cb;
512 o.o_tag = LDAP_REQ_MODIFY;
513 o.orm_modlist = agg.agg_mod;
514 o.o_req_dn = age->age_dn;
515 o.o_req_ndn = age->age_ndn;
516 o.o_relax = SLAP_CONTROL_CRITICAL;
517 o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
518 o.o_permissive_modify = 1;
519
520 o.o_bd->bd_info = (BackendInfo *)on->on_info;
521 (void)op->o_bd->be_modify( &o, &rs );
522 o.o_bd->bd_info = (BackendInfo *)on;
523
524 slap_mods_free(agg.agg_mod, 1);
525 }
526
527 return 0;
528 }
529
530 /*
531 ** Adds a group to the internal list from the passed entry.
532 ** scan specifies whether to add all maching members to the group.
533 ** modify specifies whether to modify the given group entry (when modify == 0),
534 ** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
535 ** agi - pointer to the groups and the attribute definitions
536 ** agd - the attribute definition of the added group
537 ** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
538 ** ndn - the DN of the group, can be NULL if we give a non-NULL e
539 */
540 static int
541 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
542 {
543 autogroup_entry_t **agep = &agi->agi_entry;
544 autogroup_filter_t *agf, *agf_prev = NULL;
545 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
546 LDAPURLDesc *lud = NULL;
547 Attribute *a;
548 BerValue *bv, dn;
549 int rc = 0, match = 1, null_entry = 0;
550
551 if ( e == NULL ) {
552 if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
553 LDAP_SUCCESS || e == NULL ) {
554 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
555 return 1;
556 }
557
558 null_entry = 1;
559 }
560
561 Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
562 e->e_name.bv_val, 0, 0);
563
564 if ( agi->agi_entry != NULL ) {
565 for ( ; *agep ; agep = &(*agep)->age_next ) {
566 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
567 if ( match == 0 ) {
568 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
569 return 1;
570 }
571 /* goto last */;
572 }
573 }
574
575
576 *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
577 ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
578 (*agep)->age_def = agd;
579 (*agep)->age_filter = NULL;
580 (*agep)->age_mustrefresh = 0;
581 (*agep)->age_modrdn_olddnmodified = 0;
582
583 ber_dupbv( &(*agep)->age_dn, &e->e_name );
584 ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
585
586 a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
587
588 if ( null_entry == 1 ) {
589 a = attrs_dup( a );
590 overlay_entry_release_ov( op, e, 0, on );
591 }
592
593 if( a == NULL ) {
594 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
595 } else {
596 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
597
598 agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
599
600 if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
601 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
602 /* FIXME: error? */
603 ch_free( agf );
604 continue;
605 }
606
607 agf->agf_scope = lud->lud_scope;
608
609 if ( lud->lud_dn == NULL ) {
610 BER_BVSTR( &dn, "" );
611 } else {
612 ber_str2bv( lud->lud_dn, 0, 0, &dn );
613 }
614
615 rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
616 if ( rc != LDAP_SUCCESS ) {
617 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
618 /* FIXME: error? */
619 goto cleanup;
620 }
621
622 if ( lud->lud_filter != NULL ) {
623 ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
624 agf->agf_filter = str2filter( lud->lud_filter );
625 }
626
627 if ( lud->lud_attrs != NULL ) {
628 int i;
629
630 for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
631 /* Just counting */;
632 }
633
634 if ( i > 1 ) {
635 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n",
636 bv->bv_val, 0, 0);
637 /* FIXME: error? */
638 ldap_free_urldesc( lud );
639 ch_free( agf );
640 continue;
641 }
642
643 agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
644
645 if ( agf->agf_anlist == NULL ) {
646 Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
647 lud->lud_attrs[0], 0, 0 );
648 /* FIXME: error? */
649 ldap_free_urldesc( lud );
650 ch_free( agf );
651 continue;
652 }
653 }
654
655 agf->agf_next = NULL;
656
657
658 if( (*agep)->age_filter == NULL ) {
659 (*agep)->age_filter = agf;
660 }
661
662 if( agf_prev != NULL ) {
663 agf_prev->agf_next = agf;
664 }
665
666 agf_prev = agf;
667
668 if ( scan == 1 ){
669 autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
670 }
671
672 Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
673 agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);
674
675 ldap_free_urldesc( lud );
676
677 continue;
678
679
680 cleanup:;
681
682 ldap_free_urldesc( lud );
683 ch_free( agf );
684 }
685 }
686
687 if ( null_entry == 1 ) {
688 attrs_free( a );
689 }
690 return rc;
691 }
692
693 /*
694 ** Used when opening the database to add all existing
695 ** groups from the database to our internal list.
696 */
697 static int
698 autogroup_group_add_cb( Operation *op, SlapReply *rs )
699 {
700 assert( op->o_tag == LDAP_REQ_SEARCH );
701
702 if ( rs->sr_type == REP_SEARCH ) {
703 autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private;
704
705 Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
706 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
707
708 autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
709 }
710
711 return 0;
712 }
713
714
715 /*
716 ** When adding a group, we first strip any existing members,
717 ** and add all which match the filters ourselfs.
718 */
719 static int
720 autogroup_add_entry( Operation *op, SlapReply *rs)
721 {
722 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
723 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
724 autogroup_def_t *agd = agi->agi_def;
725 autogroup_entry_t *age;
726 autogroup_filter_t *agf;
727 int rc = 0;
728
729 Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
730 op->ora_e->e_name.bv_val, 0, 0);
731
732 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
733
734 /* Check if it's a group. */
735 for ( ; agd ; agd = agd->agd_next ) {
736 if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
737 Modification mod;
738 const char *text = NULL;
739 char textbuf[1024];
740
741 mod.sm_op = LDAP_MOD_DELETE;
742 mod.sm_desc = agd->agd_member_ad;
743 mod.sm_type = agd->agd_member_ad->ad_cname;
744 mod.sm_values = NULL;
745 mod.sm_nvalues = NULL;
746
747 /* We don't want any member attributes added by the user. */
748 modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
749
750 autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0);
751 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
752 return SLAP_CB_CONTINUE;
753 }
754 }
755
756
757 for ( age = agi->agi_entry; age ; age = age->age_next ) {
758 ldap_pvt_thread_mutex_lock( &age->age_mutex );
759
760 /* Check if any of the filters are the suffix to the entry DN.
761 If yes, we can test that filter against the entry. */
762
763 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
764 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
765 rc = test_filter( op, op->ora_e, agf->agf_filter );
766 if ( rc == LDAP_COMPARE_TRUE ) {
767 if ( agf->agf_anlist ) {
768 autogroup_add_member_values_to_group( op, op->ora_e, age, agf->agf_anlist[0].an_desc );
769 } else {
770 autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age );
771 }
772 break;
773 }
774 }
775 }
776 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
777 }
778
779 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
780
781 return SLAP_CB_CONTINUE;
782 }
783
784 /*
785 ** agi - internal group and attribute definitions list
786 ** e - the group to remove from the internal list
787 */
788 static int
789 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
790 {
791 autogroup_entry_t *age = agi->agi_entry,
792 *age_prev = NULL,
793 *age_next;
794 int rc = 1;
795
796 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
797 age->age_dn.bv_val, 0, 0);
798
799 for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
800 age_next = age->age_next;
801
802 if ( age == e ) {
803 autogroup_filter_t *agf = age->age_filter,
804 *agf_next;
805
806 if ( age_prev != NULL ) {
807 age_prev->age_next = age_next;
808 } else {
809 agi->agi_entry = NULL;
810 }
811
812 ch_free( age->age_dn.bv_val );
813 ch_free( age->age_ndn.bv_val );
814
815 for( agf_next = agf ; agf_next ; agf = agf_next ){
816 agf_next = agf->agf_next;
817
818 filter_free( agf->agf_filter );
819 ch_free( agf->agf_filterstr.bv_val );
820 ch_free( agf->agf_dn.bv_val );
821 ch_free( agf->agf_ndn.bv_val );
822 anlist_free( agf->agf_anlist, 1, NULL );
823 ch_free( agf );
824 }
825
826 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
827 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
828 ch_free( age );
829
830 rc = 0;
831 return rc;
832
833 }
834 }
835
836 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0);
837
838 return rc;
839
840 }
841
842 static int
843 autogroup_delete_entry( Operation *op, SlapReply *rs)
844 {
845 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
846 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
847 autogroup_entry_t *age, *age_prev, *age_next;
848 autogroup_filter_t *agf;
849 Entry *e;
850 int matched_group = 0, rc = 0;
851
852 Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
853
854 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
855
856 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
857 LDAP_SUCCESS || e == NULL ) {
858 Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
859 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
860 return SLAP_CB_CONTINUE;
861 }
862
863 /* Check if the entry to be deleted is one of our groups. */
864 for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) {
865 age = age_next;
866 ldap_pvt_thread_mutex_lock( &age->age_mutex );
867 age_next = age->age_next;
868
869 if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
870 int match = 1;
871
872 matched_group = 1;
873
874 dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
875
876 if ( match == 0 ) {
877 autogroup_delete_group( agi, age );
878 break;
879 }
880 }
881
882 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
883 }
884
885 if ( matched_group == 1 ) {
886 overlay_entry_release_ov( op, e, 0, on );
887 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
888 return SLAP_CB_CONTINUE;
889 }
890
891 /* Check if the entry matches any of the groups.
892 If yes, we can delete the entry from that group. */
893
894 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
895 ldap_pvt_thread_mutex_lock( &age->age_mutex );
896
897 for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
898 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
899 rc = test_filter( op, e, agf->agf_filter );
900 if ( rc == LDAP_COMPARE_TRUE ) {
901 /* If the attribute is retrieved from the entry, we don't know what to delete
902 ** So the group must be entirely refreshed
903 ** But the refresh can't be done now because the entry is not deleted
904 ** So the group is marked as mustrefresh
905 */
906 if ( agf->agf_anlist ) {
907 age->age_mustrefresh = 1;
908 } else {
909 autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
910 }
911 break;
912 }
913 }
914 }
915 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
916 }
917
918 overlay_entry_release_ov( op, e, 0, on );
919 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
920
921 return SLAP_CB_CONTINUE;
922 }
923
924 static int
925 autogroup_response( Operation *op, SlapReply *rs )
926 {
927 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
928 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
929 autogroup_def_t *agd = agi->agi_def;
930 autogroup_entry_t *age;
931 autogroup_filter_t *agf;
932 BerValue new_dn, new_ndn, pdn;
933 Entry *e, *group;
934 Attribute *a, *ea;
935 int is_olddn, is_newdn, is_value_refresh, dn_equal;
936
937 /* Handle all cases where a refresh of the group is needed */
938 if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
939 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
940
941 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
942
943 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
944 /* Request detected that the group must be refreshed */
945
946 ldap_pvt_thread_mutex_lock( &age->age_mutex );
947
948 if ( age->age_mustrefresh ) {
949 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
950
951 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
952 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
953 }
954 }
955
956 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
957 }
958
959 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
960 }
961 } else if ( op->o_tag == LDAP_REQ_MODRDN ) {
962 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) {
963
964 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0);
965
966 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
967
968 if ( op->oq_modrdn.rs_newSup ) {
969 pdn = *op->oq_modrdn.rs_newSup;
970 } else {
971 dnParent( &op->o_req_dn, &pdn );
972 }
973 build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
974
975 if ( op->oq_modrdn.rs_nnewSup ) {
976 pdn = *op->oq_modrdn.rs_nnewSup;
977 } else {
978 dnParent( &op->o_req_ndn, &pdn );
979 }
980 build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
981
982 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0);
983
984 dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
985
986 if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
987 LDAP_SUCCESS || e == NULL ) {
988 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0);
989 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
990 return SLAP_CB_CONTINUE;
991 }
992
993 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
994
995
996 if ( a == NULL ) {
997 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0);
998 overlay_entry_release_ov( op, e, 0, on );
999 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1000 return SLAP_CB_CONTINUE;
1001 }
1002
1003
1004 /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
1005 for ( ; agd; agd = agd->agd_next ) {
1006
1007 if ( value_find_ex( slap_schema.si_ad_objectClass,
1008 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1009 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1010 a->a_nvals, &agd->agd_oc->soc_cname,
1011 op->o_tmpmemctx ) == 0 )
1012 {
1013 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1014 int match = 1;
1015
1016 dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
1017 if ( match == 0 ) {
1018 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0);
1019 ber_dupbv( &age->age_dn, &new_dn );
1020 ber_dupbv( &age->age_ndn, &new_ndn );
1021
1022 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1023 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1024 overlay_entry_release_ov( op, e, 0, on );
1025 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1026 return SLAP_CB_CONTINUE;
1027 }
1028 }
1029
1030 }
1031 }
1032
1033 /* For each group:
1034 1. check if the orginal entry's DN is in the group.
1035 2. chceck if the any of the group filter's base DN is a suffix of the new DN
1036
1037 If 1 and 2 are both false, we do nothing.
1038 If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
1039 If 1 is false, and 2 is true, we check the entry against the group's filters,
1040 and add it's DN to the group.
1041 If 1 is true, and 2 is false, we delete the entry's DN from the group.
1042 */
1043 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1044 is_olddn = 0;
1045 is_newdn = 0;
1046 is_value_refresh = 0;
1047
1048
1049 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1050
1051 if ( age->age_filter && age->age_filter->agf_anlist ) {
1052 ea = attrs_find( e->e_attrs, age->age_filter->agf_anlist[0].an_desc );
1053 }
1054 else {
1055 ea = NULL;
1056 }
1057
1058 if ( age->age_modrdn_olddnmodified ) {
1059 /* Resquest already marked this group to be updated */
1060 is_olddn = 1;
1061 is_value_refresh = 1;
1062 age->age_modrdn_olddnmodified = 0;
1063 } else {
1064
1065 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1066 LDAP_SUCCESS || group == NULL ) {
1067 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0);
1068
1069 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1070 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1071
1072 overlay_entry_release_ov( op, e, 0, on );
1073 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1074 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1075 return SLAP_CB_CONTINUE;
1076 }
1077
1078 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1079
1080 if ( a != NULL ) {
1081 if ( value_find_ex( age->age_def->agd_member_ad,
1082 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1083 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1084 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1085 {
1086 is_olddn = 1;
1087 }
1088
1089 }
1090
1091 overlay_entry_release_ov( op, group, 0, on );
1092
1093 }
1094
1095 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1096 if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
1097 /* TODO: should retest filter as it could imply conditions on the dn */
1098 is_newdn = 1;
1099 break;
1100 }
1101 }
1102
1103
1104 if ( is_value_refresh ) {
1105 if ( is_olddn != is_newdn ) {
1106 /* group refresh */
1107 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1108
1109 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1110 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1111 }
1112 }
1113 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1114 continue;
1115 }
1116 if ( is_olddn == 1 && is_newdn == 0 ) {
1117 if ( ea )
1118 autogroup_delete_member_values_from_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
1119 else
1120 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1121 } else
1122 if ( is_olddn == 0 && is_newdn == 1 ) {
1123 for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
1124 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1125 if ( ea )
1126 autogroup_add_member_values_to_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
1127 else
1128 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1129 break;
1130 }
1131 }
1132 } else
1133 if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
1134 if ( ea ) {
1135 /* group refresh */
1136 autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1137
1138 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1139 autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1140 }
1141 }
1142 else {
1143 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1144 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1145 }
1146 }
1147
1148 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1149 }
1150
1151 op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1152 op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1153
1154 overlay_entry_release_ov( op, e, 0, on );
1155
1156 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1157 }
1158 }
1159
1160 if ( op->o_tag == LDAP_REQ_MODIFY ) {
1161 if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) {
1162 Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0);
1163
1164 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1165
1166 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1167 LDAP_SUCCESS || e == NULL ) {
1168 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1169 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1170 return SLAP_CB_CONTINUE;
1171 }
1172
1173 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1174
1175
1176 if ( a == NULL ) {
1177 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1178 overlay_entry_release_ov( op, e, 0, on );
1179 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1180 return SLAP_CB_CONTINUE;
1181 }
1182
1183 /* If we modify a group's memberURL, we have to delete all of it's members,
1184 and add them anew, because we cannot tell from which memberURL a member was added. */
1185 for ( ; agd; agd = agd->agd_next ) {
1186
1187 if ( value_find_ex( slap_schema.si_ad_objectClass,
1188 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1189 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1190 a->a_nvals, &agd->agd_oc->soc_cname,
1191 op->o_tmpmemctx ) == 0 )
1192 {
1193 Modifications *m;
1194 int match = 1;
1195
1196 m = op->orm_modlist;
1197
1198 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1199 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1200
1201 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1202
1203 if ( match == 0 ) {
1204 for ( ; m ; m = m->sml_next ) {
1205 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
1206 autogroup_def_t *group_agd = age->age_def;
1207 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
1208 op->o_req_dn.bv_val, 0, 0);
1209
1210 overlay_entry_release_ov( op, e, 0, on );
1211
1212 autogroup_delete_member_from_group( op, NULL, NULL, age );
1213 autogroup_delete_group( agi, age );
1214
1215 autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
1216
1217 overlay_entry_release_ov( op, e, 0, on );
1218 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1219 return SLAP_CB_CONTINUE;
1220 }
1221 }
1222
1223 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1224 break;
1225 }
1226
1227 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1228 }
1229
1230 overlay_entry_release_ov( op, e, 0, on );
1231 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1232 return SLAP_CB_CONTINUE;
1233 }
1234 }
1235
1236 /* When modifing any of the attributes of an entry, we must
1237 check if the entry is in any of our groups, and if
1238 the modified entry maches any of the filters of that group.
1239
1240 If the entry exists in a group, but the modified attributes do
1241 not match any of the group's filters, we delete the entry from that group.
1242 If the entry doesn't exist in a group, but matches a filter,
1243 we add it to that group.
1244 */
1245 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1246 is_olddn = 0;
1247 is_newdn = 0;
1248
1249
1250 ldap_pvt_thread_mutex_lock( &age->age_mutex );
1251
1252 if ( age->age_filter && age->age_filter->agf_anlist ) {
1253 ea = attrs_find( e->e_attrs, age->age_filter->agf_anlist[0].an_desc );
1254 }
1255 else {
1256 ea = NULL;
1257 }
1258
1259 if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1260 LDAP_SUCCESS || group == NULL ) {
1261 Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
1262 age->age_dn.bv_val, 0, 0);
1263
1264 overlay_entry_release_ov( op, e, 0, on );
1265 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1266 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1267 return SLAP_CB_CONTINUE;
1268 }
1269
1270 a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1271
1272 if ( a != NULL ) {
1273 if ( value_find_ex( age->age_def->agd_member_ad,
1274 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1275 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1276 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1277 {
1278 is_olddn = 1;
1279 }
1280
1281 }
1282
1283 overlay_entry_release_ov( op, group, 0, on );
1284
1285 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1286 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1287 if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1288 is_newdn = 1;
1289 break;
1290 }
1291 }
1292 }
1293
1294 if ( is_olddn == 1 && is_newdn == 0 ) {
1295 if(ea)
1296 autogroup_delete_member_values_from_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
1297 else
1298 autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1299 } else
1300 if ( is_olddn == 0 && is_newdn == 1 ) {
1301 if(ea)
1302 autogroup_add_member_values_to_group( op, e, age, age->age_filter->agf_anlist[0].an_desc );
1303 else
1304 autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1305 }
1306
1307 ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1308 }
1309
1310 overlay_entry_release_ov( op, e, 0, on );
1311
1312 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1313 }
1314 }
1315
1316 return SLAP_CB_CONTINUE;
1317 }
1318
1319 /*
1320 ** Detect if filter contains a memberOf check for dn
1321 */
1322 static int
1323 autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad )
1324 {
1325 int result = 0;
1326 if ( f == NULL ) return 0;
1327
1328 switch ( f->f_choice & SLAPD_FILTER_MASK ) {
1329 case LDAP_FILTER_AND:
1330 case LDAP_FILTER_OR:
1331 case LDAP_FILTER_NOT:
1332 for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) {
1333 result = result || autogroup_memberOf_filter( f, dn, memberof_ad );
1334 }
1335 break;
1336 case LDAP_FILTER_EQUALITY:
1337 result = ( f->f_ava->aa_desc == memberof_ad &&
1338 ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 );
1339 break;
1340 default:
1341 break;
1342 }
1343
1344 return result;
1345 }
1346
1347 /*
1348 ** When modifing a group, we must deny any modifications to the member attribute,
1349 ** because the group would be inconsistent.
1350 */
1351 static int
1352 autogroup_modify_entry( Operation *op, SlapReply *rs)
1353 {
1354 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1355 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1356 autogroup_def_t *agd = agi->agi_def;
1357 autogroup_entry_t *age;
1358 Entry *e;
1359 Attribute *a;
1360
1361 if ( get_manageDSAit( op ) ) {
1362 return SLAP_CB_CONTINUE;
1363 }
1364
1365 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1366 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1367
1368 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1369 LDAP_SUCCESS || e == NULL ) {
1370 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1371 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1372 return SLAP_CB_CONTINUE;
1373 }
1374
1375 /* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */
1376 for ( age = agi->agi_entry; age ; age = age->age_next ) {
1377 autogroup_filter_t *agf;
1378 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1379 if ( agf->agf_anlist ) {
1380 Modifications *m;
1381 for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
1382 if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
1383 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1384 int rc = test_filter( op, e, agf->agf_filter );
1385 if ( rc == LDAP_COMPARE_TRUE ) {
1386 age->age_mustrefresh = 1;
1387 }
1388 }
1389 }
1390 }
1391 }
1392
1393 if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) {
1394 age->age_mustrefresh = 1;
1395 }
1396 }
1397 }
1398
1399 a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1400
1401 if ( a == NULL ) {
1402 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0);
1403 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1404 return SLAP_CB_CONTINUE;
1405 }
1406
1407
1408 for ( ; agd; agd = agd->agd_next ) {
1409
1410 if ( value_find_ex( slap_schema.si_ad_objectClass,
1411 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1412 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1413 a->a_nvals, &agd->agd_oc->soc_cname,
1414 op->o_tmpmemctx ) == 0 )
1415 {
1416 Modifications *m;
1417 int match = 1;
1418
1419 m = op->orm_modlist;
1420
1421 for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1422 dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1423
1424 if ( match == 0 ) {
1425 for ( ; m ; m = m->sml_next ) {
1426 if ( m->sml_desc == age->age_def->agd_member_ad ) {
1427 overlay_entry_release_ov( op, e, 0, on );
1428 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1429 Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0);
1430 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1431 return LDAP_CONSTRAINT_VIOLATION;
1432 }
1433 }
1434 break;
1435 }
1436 }
1437
1438 overlay_entry_release_ov( op, e, 0, on );
1439 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1440 return SLAP_CB_CONTINUE;
1441 }
1442 }
1443
1444 overlay_entry_release_ov( op, e, 0, on );
1445 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1446 return SLAP_CB_CONTINUE;
1447 }
1448
1449 /*
1450 ** Detect if the olddn is part of a group and so if the group should be refreshed
1451 */
1452 static int
1453 autogroup_modrdn_entry( Operation *op, SlapReply *rs)
1454 {
1455 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1456 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1457 autogroup_entry_t *age;
1458 Entry *e;
1459
1460 if ( get_manageDSAit( op ) ) {
1461 return SLAP_CB_CONTINUE;
1462 }
1463
1464 Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0);
1465 ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1466
1467 if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1468 LDAP_SUCCESS || e == NULL ) {
1469 Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0);
1470 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1471 return SLAP_CB_CONTINUE;
1472 }
1473
1474 /* Must check if a dn is modified */
1475 for ( age = agi->agi_entry; age ; age = age->age_next ) {
1476 autogroup_filter_t *agf;
1477 for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1478 if ( agf->agf_anlist ) {
1479 if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1480 int rc = test_filter( op, e, agf->agf_filter );
1481 if ( rc == LDAP_COMPARE_TRUE ) {
1482 age->age_modrdn_olddnmodified = 1;
1483 }
1484 }
1485 }
1486 }
1487 }
1488
1489 overlay_entry_release_ov( op, e, 0, on );
1490 ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1491 return SLAP_CB_CONTINUE;
1492 }
1493
1494 /*
1495 ** Builds a filter for searching for the
1496 ** group entries, according to the objectClass.
1497 */
1498 static int
1499 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1500 {
1501 char *ptr;
1502
1503 Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0);
1504
1505 op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1506 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1507 + agd->agd_oc->soc_cname.bv_len;
1508 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1509 *ptr++ = '(';
1510 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1511 *ptr++ = '=';
1512 ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1513 *ptr++ = ')';
1514 *ptr = '\0';
1515
1516 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1517
1518 assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1519
1520 return 0;
1521 }
1522
1523 enum {
1524 AG_ATTRSET = 1,
1525 AG_MEMBER_OF_AD,
1526 AG_LAST
1527 };
1528
1529 static ConfigDriver ag_cfgen;
1530
1531 static ConfigTable agcfg[] = {
1532 { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1533 3, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1534 "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' "
1535 "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1536 "EQUALITY caseIgnoreMatch "
1537 "SYNTAX OMsDirectoryString "
1538 "X-ORDERED 'VALUES' )",
1539 NULL, NULL },
1540
1541 { "autogroup-memberof-ad", "memberOf attribute",
1542 2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen,
1543 "( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' "
1544 "DESC 'memberOf attribute' "
1545 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1546 NULL, NULL },
1547
1548 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1549 };
1550
1551 static ConfigOCs agocs[] = {
1552 { "( OLcfgCtOc:2.1 "
1553 "NAME 'olcAutomaticGroups' "
1554 "DESC 'Automatic groups configuration' "
1555 "SUP olcOverlayConfig "
1556 "MAY ( "
1557 "olcAGattrSet "
1558 "$ olcAGmemberOfAd "
1559 ")"
1560 ")",
1561 Cft_Overlay, agcfg, NULL, NULL },
1562 { NULL, 0, NULL }
1563 };
1564
1565
1566 static int
1567 ag_cfgen( ConfigArgs *c )
1568 {
1569 slap_overinst *on = (slap_overinst *)c->bi;
1570 autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private;
1571 autogroup_def_t *agd;
1572 autogroup_entry_t *age;
1573
1574 int rc = 0, i;
1575
1576 Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0);
1577
1578 if( agi == NULL ) {
1579 agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1580 ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1581 agi->agi_def = NULL;
1582 agi->agi_entry = NULL;
1583 on->on_bi.bi_private = (void *)agi;
1584 }
1585
1586 agd = agi->agi_def;
1587 age = agi->agi_entry;
1588
1589 if ( c->op == SLAP_CONFIG_EMIT ) {
1590
1591 switch( c->type ){
1592 case AG_ATTRSET:
1593 for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1594 struct berval bv;
1595 char *ptr = c->cr_msg;
1596
1597 assert(agd->agd_oc != NULL);
1598 assert(agd->agd_member_url_ad != NULL);
1599 assert(agd->agd_member_ad != NULL);
1600
1601 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1602 SLAP_X_ORDERED_FMT "%s %s %s", i,
1603 agd->agd_oc->soc_cname.bv_val,
1604 agd->agd_member_url_ad->ad_cname.bv_val,
1605 agd->agd_member_ad->ad_cname.bv_val );
1606
1607 bv.bv_val = c->cr_msg;
1608 bv.bv_len = ptr - bv.bv_val;
1609 value_add_one ( &c->rvalue_vals, &bv );
1610
1611 }
1612 break;
1613
1614 case AG_MEMBER_OF_AD:
1615 if ( agi->agi_memberof_ad != NULL ){
1616 value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname );
1617 }
1618 break;
1619
1620 default:
1621 assert( 0 );
1622 return 1;
1623 }
1624
1625 return rc;
1626
1627 }else if ( c->op == LDAP_MOD_DELETE ) {
1628 if ( c->valx < 0) {
1629 autogroup_def_t *agd_next;
1630 autogroup_entry_t *age_next;
1631 autogroup_filter_t *agf = age->age_filter,
1632 *agf_next;
1633
1634 for ( agd_next = agd; agd_next; agd = agd_next ) {
1635 agd_next = agd->agd_next;
1636
1637 ch_free( agd );
1638 }
1639
1640 for ( age_next = age ; age_next ; age = age_next ) {
1641 age_next = age->age_next;
1642
1643 ch_free( age->age_dn.bv_val );
1644 ch_free( age->age_ndn.bv_val );
1645
1646 for( agf_next = agf ; agf_next ; agf = agf_next ){
1647 agf_next = agf->agf_next;
1648
1649 filter_free( agf->agf_filter );
1650 ch_free( agf->agf_filterstr.bv_val );
1651 ch_free( agf->agf_dn.bv_val );
1652 ch_free( agf->agf_ndn.bv_val );
1653 anlist_free( agf->agf_anlist, 1, NULL );
1654 ch_free( agf );
1655 }
1656
1657 ldap_pvt_thread_mutex_init( &age->age_mutex );
1658 ch_free( age );
1659 }
1660
1661 ch_free( agi );
1662 on->on_bi.bi_private = NULL;
1663
1664 } else {
1665 autogroup_def_t **agdp;
1666 autogroup_entry_t *age_next, *age_prev;
1667 autogroup_filter_t *agf,
1668 *agf_next;
1669
1670 for ( i = 0, agdp = &agi->agi_def;
1671 i < c->valx; i++ )
1672 {
1673 if ( *agdp == NULL) {
1674 return 1;
1675 }
1676 agdp = &(*agdp)->agd_next;
1677 }
1678
1679 agd = *agdp;
1680 *agdp = agd->agd_next;
1681
1682 for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1683 age_next = age->age_next;
1684
1685 if( age->age_def == agd ) {
1686 agf = age->age_filter;
1687
1688 ch_free( age->age_dn.bv_val );
1689 ch_free( age->age_ndn.bv_val );
1690
1691 for ( agf_next = agf; agf_next ; agf = agf_next ) {
1692 agf_next = agf->agf_next;
1693 filter_free( agf->agf_filter );
1694 ch_free( agf->agf_filterstr.bv_val );
1695 ch_free( agf->agf_dn.bv_val );
1696 ch_free( agf->agf_ndn.bv_val );
1697 anlist_free( agf->agf_anlist, 1, NULL );
1698 ch_free( agf );
1699 }
1700
1701 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1702 ch_free( age );
1703
1704 age = age_prev;
1705
1706 if( age_prev != NULL ) {
1707 age_prev->age_next = age_next;
1708 }
1709 }
1710 }
1711
1712 ch_free( agd );
1713 agd = agi->agi_def;
1714
1715 }
1716
1717 return rc;
1718 }
1719
1720 switch(c->type){
1721 case AG_ATTRSET: {
1722 autogroup_def_t **agdp,
1723 *agd_next = NULL;
1724 ObjectClass *oc = NULL;
1725 AttributeDescription *member_url_ad = NULL,
1726 *member_ad = NULL;
1727 const char *text;
1728
1729
1730 oc = oc_find( c->argv[ 1 ] );
1731 if( oc == NULL ){
1732 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1733 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1734 "unable to find ObjectClass \"%s\"",
1735 c->argv[ 1 ] );
1736 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1737 c->log, c->cr_msg, 0 );
1738 return 1;
1739 }
1740
1741
1742 rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1743 if( rc != LDAP_SUCCESS ) {
1744 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1745 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1746 "unable to find AttributeDescription \"%s\"",
1747 c->argv[ 2 ] );
1748 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1749 c->log, c->cr_msg, 0 );
1750 return 1;
1751 }
1752
1753 if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1754 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1755 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1756 "AttributeDescription \"%s\" ",
1757 "must be of a subtype \"labeledURI\"",
1758 c->argv[ 2 ] );
1759 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1760 c->log, c->cr_msg, 0 );
1761 return 1;
1762 }
1763
1764 rc = slap_str2ad( c->argv[3], &member_ad, &text );
1765 if( rc != LDAP_SUCCESS ) {
1766 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1767 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1768 "unable to find AttributeDescription \"%s\"",
1769 c->argv[ 3 ] );
1770 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1771 c->log, c->cr_msg, 0 );
1772 return 1;
1773 }
1774
1775 for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1776 /* The same URL attribute / member attribute pair
1777 * cannot be repeated */
1778
1779 if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1780 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1781 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1782 "URL attributeDescription \"%s\" already mapped",
1783 member_ad->ad_cname.bv_val );
1784 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1785 c->log, c->cr_msg, 0 );
1786 /* return 1; //warning*/
1787 }
1788 }
1789
1790 if ( c->valx > 0 ) {
1791 int i;
1792
1793 for ( i = 0, agdp = &agi->agi_def ;
1794 i < c->valx; i++ )
1795 {
1796 if ( *agdp == NULL ) {
1797 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1798 "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1799 "invalid index {%d}",
1800 c->valx );
1801 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1802 c->log, c->cr_msg, 0 );
1803
1804 return 1;
1805 }
1806 agdp = &(*agdp)->agd_next;
1807 }
1808 agd_next = *agdp;
1809
1810 } else {
1811 for ( agdp = &agi->agi_def; *agdp;
1812 agdp = &(*agdp)->agd_next )
1813 /* goto last */;
1814 }
1815
1816 *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
1817
1818 (*agdp)->agd_oc = oc;
1819 (*agdp)->agd_member_url_ad = member_url_ad;
1820 (*agdp)->agd_member_ad = member_ad;
1821 (*agdp)->agd_next = agd_next;
1822
1823 } break;
1824
1825 case AG_MEMBER_OF_AD: {
1826 AttributeDescription *memberof_ad = NULL;
1827 const char *text;
1828
1829 rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text );
1830 if( rc != LDAP_SUCCESS ) {
1831 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1832 "\"autogroup-memberof-ad <memberof-ad>\": "
1833 "unable to find AttributeDescription \"%s\"",
1834 c->argv[ 1 ] );
1835 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1836 c->log, c->cr_msg, 0 );
1837 return 1;
1838 }
1839
1840 if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */
1841 && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */
1842 {
1843 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1844 "memberof attribute=\"%s\" must either "
1845 "have DN (%s) or nameUID (%s) syntax",
1846 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
1847 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1848 c->log, c->cr_msg, 0 );
1849 return 1;
1850 }
1851
1852 agi->agi_memberof_ad = memberof_ad;
1853
1854 } break;
1855
1856 default:
1857 rc = 1;
1858 break;
1859 }
1860
1861 return rc;
1862 }
1863
1864 extern int slapMode;
1865
1866 /*
1867 ** Do a search for all the groups in the
1868 ** database, and add them to out internal list.
1869 */
1870 static int
1871 autogroup_db_open(
1872 BackendDB *be,
1873 ConfigReply *cr )
1874 {
1875 slap_overinst *on = (slap_overinst *) be->bd_info;
1876 autogroup_info_t *agi = on->on_bi.bi_private;
1877 autogroup_def_t *agd;
1878 autogroup_sc_t ags;
1879 Operation *op;
1880 slap_callback cb = { 0 };
1881
1882 void *thrctx = ldap_pvt_thread_pool_context();
1883 Connection conn = { 0 };
1884 OperationBuffer opbuf;
1885
1886 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
1887
1888 if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
1889 return 0;
1890 }
1891
1892 connection_fake_init( &conn, &opbuf, thrctx );
1893 op = &opbuf.ob_op;
1894
1895 op->ors_attrsonly = 0;
1896 op->o_tag = LDAP_REQ_SEARCH;
1897 op->o_dn = be->be_rootdn;
1898 op->o_ndn = be->be_rootndn;
1899
1900 op->o_req_dn = be->be_suffix[0];
1901 op->o_req_ndn = be->be_nsuffix[0];
1902
1903 op->ors_scope = LDAP_SCOPE_SUBTREE;
1904 op->ors_deref = LDAP_DEREF_NEVER;
1905 op->ors_limit = NULL;
1906 op->ors_tlimit = SLAP_NO_LIMIT;
1907 op->ors_slimit = SLAP_NO_LIMIT;
1908 op->ors_attrs = slap_anlist_no_attrs;
1909
1910 op->o_bd = be;
1911 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1912
1913 ags.ags_info = agi;
1914 cb.sc_private = &ags;
1915 cb.sc_response = autogroup_group_add_cb;
1916 cb.sc_cleanup = NULL;
1917 cb.sc_next = NULL;
1918
1919 op->o_callback = &cb;
1920
1921 for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
1922 SlapReply rs = { REP_RESULT };
1923
1924 autogroup_build_def_filter(agd, op);
1925
1926 ags.ags_def = agd;
1927
1928 op->o_bd->be_search( op, &rs );
1929
1930 filter_free_x( op, op->ors_filter, 1 );
1931 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1932 }
1933
1934 if( ! agi->agi_memberof_ad ){
1935 int rc;
1936 const char *text = NULL;
1937
1938 rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text );
1939 if ( rc != LDAP_SUCCESS ) {
1940 Debug( LDAP_DEBUG_ANY, "autogroup_db_open: "
1941 "unable to find attribute=\"%s\": %s (%d)\n",
1942 SLAPD_MEMBEROF_ATTR, text, rc );
1943 return rc;
1944 }
1945 }
1946
1947 return 0;
1948 }
1949
1950 static int
1951 autogroup_db_close(
1952 BackendDB *be,
1953 ConfigReply *cr )
1954 {
1955 slap_overinst *on = (slap_overinst *) be->bd_info;
1956
1957 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0);
1958
1959 if ( on->on_bi.bi_private ) {
1960 autogroup_info_t *agi = on->on_bi.bi_private;
1961 autogroup_entry_t *age = agi->agi_entry,
1962 *age_next;
1963 autogroup_filter_t *agf, *agf_next;
1964
1965 for ( age_next = age; age_next; age = age_next ) {
1966 age_next = age->age_next;
1967
1968 ch_free( age->age_dn.bv_val );
1969 ch_free( age->age_ndn.bv_val );
1970
1971 agf = age->age_filter;
1972
1973 for ( agf_next = agf; agf_next; agf = agf_next ) {
1974 agf_next = agf->agf_next;
1975
1976 filter_free( agf->agf_filter );
1977 ch_free( agf->agf_filterstr.bv_val );
1978 ch_free( agf->agf_dn.bv_val );
1979 ch_free( agf->agf_ndn.bv_val );
1980 anlist_free( agf->agf_anlist, 1, NULL );
1981 ch_free( agf );
1982 }
1983
1984 ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1985 ch_free( age );
1986 }
1987 }
1988
1989 return 0;
1990 }
1991
1992 static int
1993 autogroup_db_destroy(
1994 BackendDB *be,
1995 ConfigReply *cr )
1996 {
1997 slap_overinst *on = (slap_overinst *) be->bd_info;
1998
1999 Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0);
2000
2001 if ( on->on_bi.bi_private ) {
2002 autogroup_info_t *agi = on->on_bi.bi_private;
2003 autogroup_def_t *agd = agi->agi_def,
2004 *agd_next;
2005
2006 for ( agd_next = agd; agd_next; agd = agd_next ) {
2007 agd_next = agd->agd_next;
2008
2009 ch_free( agd );
2010 }
2011
2012 ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
2013 ch_free( agi );
2014 }
2015
2016 return 0;
2017 }
2018
2019 static slap_overinst autogroup = { { NULL } };
2020
2021 static
2022 int
2023 autogroup_initialize(void)
2024 {
2025 int rc = 0;
2026 autogroup.on_bi.bi_type = "autogroup";
2027
2028 autogroup.on_bi.bi_db_open = autogroup_db_open;
2029 autogroup.on_bi.bi_db_close = autogroup_db_close;
2030 autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
2031
2032 autogroup.on_bi.bi_op_add = autogroup_add_entry;
2033 autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
2034 autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
2035 autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
2036
2037 autogroup.on_response = autogroup_response;
2038
2039 autogroup.on_bi.bi_cf_ocs = agocs;
2040
2041 rc = config_register_schema( agcfg, agocs );
2042 if ( rc ) {
2043 return rc;
2044 }
2045
2046 return overlay_register( &autogroup );
2047 }
2048
2049 int
2050 init_module( int argc, char *argv[] )
2051 {
2052 return autogroup_initialize();
2053 }
2054