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