1 /* $NetBSD: dynlist.c,v 1.3 2021/08/14 16:15:02 christos Exp $ */
2
3 /* dynlist.c - dynamic list overlay */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2003-2021 The OpenLDAP Foundation.
8 * Portions Copyright 2004-2005 Pierangelo Masarati.
9 * Portions Copyright 2008 Emmanuel Dreyfus.
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 Pierangelo Masarati
22 * for SysNet s.n.c., for inclusion in OpenLDAP Software.
23 */
24
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: dynlist.c,v 1.3 2021/08/14 16:15:02 christos Exp $");
27
28 #include "portable.h"
29
30 #ifdef SLAPD_OVER_DYNLIST
31
32 #if SLAPD_OVER_DYNGROUP != SLAPD_MOD_STATIC
33 #define TAKEOVER_DYNGROUP
34 #endif
35
36 #include <stdio.h>
37
38 #include <ac/string.h>
39
40 #include "slap.h"
41 #include "slap-config.h"
42 #include "lutil.h"
43
44 static AttributeDescription *ad_dgIdentity, *ad_dgAuthz;
45 static AttributeDescription *ad_memberOf;
46
47 typedef struct dynlist_map_t {
48 AttributeDescription *dlm_member_ad;
49 AttributeDescription *dlm_mapped_ad;
50 AttributeDescription *dlm_memberOf_ad;
51 ObjectClass *dlm_static_oc;
52 int dlm_memberOf_nested;
53 int dlm_member_oper;
54 int dlm_memberOf_oper;
55 struct dynlist_map_t *dlm_next;
56 } dynlist_map_t;
57
58 typedef struct dynlist_info_t {
59 ObjectClass *dli_oc;
60 AttributeDescription *dli_ad;
61 struct dynlist_map_t *dli_dlm;
62 struct berval dli_uri;
63 LDAPURLDesc *dli_lud;
64 struct berval dli_uri_nbase;
65 Filter *dli_uri_filter;
66 struct berval dli_default_filter;
67 struct dynlist_info_t *dli_next;
68 } dynlist_info_t;
69
70 typedef struct dynlist_gen_t {
71 dynlist_info_t *dlg_dli;
72 int dlg_memberOf;
73 } dynlist_gen_t;
74
75 #define DYNLIST_USAGE \
76 "\"dynlist-attrset <oc> [uri] <URL-ad> [[<mapped-ad>:]<member-ad>[+<memberOf-ad>[@<static-oc>[*]] ...]\": "
77
78 static int
ad_infilter(AttributeDescription * ad,Filter * f)79 ad_infilter( AttributeDescription *ad, Filter *f )
80 {
81 if ( !f )
82 return 0;
83
84 switch( f->f_choice & SLAPD_FILTER_MASK ) {
85 case SLAPD_FILTER_COMPUTED:
86 return 0;
87 case LDAP_FILTER_PRESENT:
88 return f->f_desc == ad;
89 case LDAP_FILTER_EQUALITY:
90 case LDAP_FILTER_GE:
91 case LDAP_FILTER_LE:
92 case LDAP_FILTER_APPROX:
93 case LDAP_FILTER_SUBSTRINGS:
94 case LDAP_FILTER_EXT:
95 return f->f_av_desc == ad;
96 case LDAP_FILTER_AND:
97 case LDAP_FILTER_OR:
98 case LDAP_FILTER_NOT: {
99 for ( f = f->f_list; f; f = f->f_next )
100 if ( ad_infilter( ad, f ))
101 return 1;
102 }
103 }
104 return 0;
105 }
106
107 static int
dynlist_make_filter(Operation * op,Entry * e,dynlist_info_t * dli,const char * url,struct berval * oldf,struct berval * newf)108 dynlist_make_filter( Operation *op, Entry *e, dynlist_info_t *dli, const char *url, struct berval *oldf, struct berval *newf )
109 {
110 char *ptr;
111 int needBrackets = 0;
112
113 assert( oldf != NULL );
114 assert( newf != NULL );
115 assert( !BER_BVISNULL( oldf ) );
116 assert( !BER_BVISEMPTY( oldf ) );
117
118 if ( oldf->bv_val[0] != '(' ) {
119 Debug( LDAP_DEBUG_ANY, "%s: dynlist, DN=\"%s\": missing parentheses in URI=\"%s\" filter\n",
120 op->o_log_prefix, e->e_name.bv_val, url );
121 needBrackets = 2;
122 }
123
124 newf->bv_len = STRLENOF( "(&(!(objectClass=" "))" ")" )
125 + dli->dli_oc->soc_cname.bv_len + oldf->bv_len + needBrackets;
126 newf->bv_val = op->o_tmpalloc( newf->bv_len + 1, op->o_tmpmemctx );
127 if ( newf->bv_val == NULL ) {
128 return -1;
129 }
130 ptr = lutil_strcopy( newf->bv_val, "(&(!(objectClass=" );
131 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
132 ptr = lutil_strcopy( ptr, "))" );
133 if ( needBrackets ) *ptr++ = '(';
134 ptr = lutil_strcopy( ptr, oldf->bv_val );
135 if ( needBrackets ) *ptr++ = ')';
136 ptr = lutil_strcopy( ptr, ")" );
137 newf->bv_len = ptr - newf->bv_val;
138
139 return 0;
140 }
141
142 /* dynlist_sc_update() callback info set by dynlist_prepare_entry() */
143 typedef struct dynlist_sc_t {
144 dynlist_info_t *dlc_dli;
145 Entry *dlc_e;
146 char **dlc_attrs;
147 } dynlist_sc_t;
148
149 static int
dynlist_sc_update(Operation * op,SlapReply * rs)150 dynlist_sc_update( Operation *op, SlapReply *rs )
151 {
152 Entry *e;
153 Attribute *a;
154 int opattrs,
155 userattrs;
156 AccessControlState acl_state = ACL_STATE_INIT;
157
158 dynlist_sc_t *dlc;
159 dynlist_map_t *dlm;
160
161 if ( rs->sr_type != REP_SEARCH ) {
162 return 0;
163 }
164
165 dlc = (dynlist_sc_t *)op->o_callback->sc_private;
166 e = dlc->dlc_e;
167
168 assert( e != NULL );
169 assert( rs->sr_entry != NULL );
170
171 /* test access to entry */
172 if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
173 NULL, ACL_READ, NULL ) )
174 {
175 goto done;
176 }
177
178 /* if there is only one member_ad, and it's not mapped,
179 * consider it as old-style member listing */
180 dlm = dlc->dlc_dli->dli_dlm;
181 if ( dlm && dlm->dlm_mapped_ad == NULL && dlm->dlm_next == NULL && dlc->dlc_attrs == NULL ) {
182 /* if access allowed, try to add values, emulating permissive
183 * control to silently ignore duplicates */
184 if ( access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
185 NULL, ACL_READ, NULL ) )
186 {
187 Modification mod;
188 const char *text = NULL;
189 char textbuf[1024];
190 struct berval vals[ 2 ], nvals[ 2 ];
191
192 vals[ 0 ] = rs->sr_entry->e_name;
193 BER_BVZERO( &vals[ 1 ] );
194 nvals[ 0 ] = rs->sr_entry->e_nname;
195 BER_BVZERO( &nvals[ 1 ] );
196
197 mod.sm_op = LDAP_MOD_ADD;
198 mod.sm_desc = dlm->dlm_member_ad;
199 mod.sm_type = dlm->dlm_member_ad->ad_cname;
200 mod.sm_values = vals;
201 mod.sm_nvalues = nvals;
202 mod.sm_numvals = 1;
203
204 (void)modify_add_values( e, &mod, /* permissive */ 1,
205 &text, textbuf, sizeof( textbuf ) );
206 }
207
208 goto done;
209 }
210
211 opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
212 userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
213
214 for ( a = rs->sr_entry->e_attrs; a != NULL; a = a->a_next ) {
215 BerVarray vals, nvals = NULL;
216 int i, j,
217 is_oc = a->a_desc == slap_schema.si_ad_objectClass;
218
219 /* if attribute is not requested, skip it */
220 if ( rs->sr_attrs == NULL ) {
221 if ( is_at_operational( a->a_desc->ad_type ) ) {
222 continue;
223 }
224
225 } else {
226 if ( is_at_operational( a->a_desc->ad_type ) ) {
227 if ( !opattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
228 {
229 continue;
230 }
231
232 } else {
233 if ( !userattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
234 {
235 continue;
236 }
237 }
238 }
239
240 /* test access to attribute */
241 if ( op->ors_attrsonly ) {
242 if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL,
243 ACL_READ, &acl_state ) )
244 {
245 continue;
246 }
247 }
248
249 /* single-value check: keep first only */
250 if ( is_at_single_value( a->a_desc->ad_type ) ) {
251 if ( attr_find( e->e_attrs, a->a_desc ) != NULL ) {
252 continue;
253 }
254 }
255
256 /* test access to attribute */
257 i = a->a_numvals;
258
259 vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
260 if ( a->a_nvals != a->a_vals ) {
261 nvals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
262 }
263
264 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
265 if ( is_oc ) {
266 ObjectClass *soc = oc_bvfind( &a->a_vals[i] );
267
268 if ( soc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) {
269 continue;
270 }
271 }
272
273 if ( access_allowed( op, rs->sr_entry, a->a_desc,
274 &a->a_nvals[i], ACL_READ, &acl_state ) )
275 {
276 vals[j] = a->a_vals[i];
277 if ( nvals ) {
278 nvals[j] = a->a_nvals[i];
279 }
280 j++;
281 }
282 }
283
284 /* if access allowed, try to add values, emulating permissive
285 * control to silently ignore duplicates */
286 if ( j != 0 ) {
287 Modification mod;
288 const char *text = NULL;
289 char textbuf[1024];
290 dynlist_map_t *dlm;
291 AttributeDescription *ad;
292
293 BER_BVZERO( &vals[j] );
294 if ( nvals ) {
295 BER_BVZERO( &nvals[j] );
296 }
297
298 ad = a->a_desc;
299 for ( dlm = dlc->dlc_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
300 if ( dlm->dlm_member_ad == a->a_desc ) {
301 if ( dlm->dlm_mapped_ad ) {
302 ad = dlm->dlm_mapped_ad;
303 }
304 break;
305 }
306 }
307
308 mod.sm_op = LDAP_MOD_ADD;
309 mod.sm_desc = ad;
310 mod.sm_type = ad->ad_cname;
311 mod.sm_values = vals;
312 mod.sm_nvalues = nvals;
313 mod.sm_numvals = j;
314
315 (void)modify_add_values( e, &mod, /* permissive */ 1,
316 &text, textbuf, sizeof( textbuf ) );
317 }
318
319 op->o_tmpfree( vals, op->o_tmpmemctx );
320 if ( nvals ) {
321 op->o_tmpfree( nvals, op->o_tmpmemctx );
322 }
323 }
324
325 done:;
326 if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
327 entry_free( rs->sr_entry );
328 rs->sr_entry = NULL;
329 rs->sr_flags &= ~REP_ENTRY_MASK;
330 }
331
332 return 0;
333 }
334
335 typedef struct dynlist_name_t {
336 struct berval dy_name;
337 dynlist_info_t *dy_dli;
338 AttributeDescription *dy_staticmember;
339 int dy_seen;
340 int dy_numuris;
341 TAvlnode *dy_subs;
342 TAvlnode *dy_sups;
343 LDAPURLDesc *dy_uris[];
344 } dynlist_name_t;
345
346 static void
dynlist_urlmembers(Operation * op,dynlist_name_t * dyn,slap_callback * sc)347 dynlist_urlmembers( Operation *op, dynlist_name_t *dyn, slap_callback *sc )
348 {
349 Operation o = *op;
350 LDAPURLDesc *ludp;
351 int i;
352
353 o.ors_deref = LDAP_DEREF_NEVER;
354 o.ors_limit = NULL;
355 o.ors_tlimit = SLAP_NO_LIMIT;
356 o.ors_slimit = SLAP_NO_LIMIT;
357 o.ors_attrs = NULL;
358 memset( o.o_ctrlflag, 0, sizeof( o.o_ctrlflag ));
359 o.o_callback = sc;
360
361 for (i=0; i<dyn->dy_numuris; i++) {
362 ludp = dyn->dy_uris[i];
363 if ( ludp->lud_attrs )
364 continue;
365 o.o_req_dn.bv_val = ludp->lud_dn;
366 o.o_req_dn.bv_len = ludp->lud_port;
367 o.o_req_ndn = o.o_req_dn;
368 o.ors_scope = ludp->lud_scope;
369 o.ors_filter = (Filter *)ludp->lud_filter;
370 filter2bv_x( op, o.ors_filter, &o.ors_filterstr );
371 o.o_bd = select_backend( &o.o_req_ndn, 1 );
372 if ( o.o_bd && o.o_bd->be_search ) {
373 SlapReply r = { REP_SEARCH };
374 r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
375 o.o_managedsait = SLAP_CONTROL_CRITICAL;
376 (void)o.o_bd->be_search( &o, &r );
377 }
378 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
379 }
380 }
381
382 static void
dynlist_nested_memberOf(Entry * e,AttributeDescription * ad,TAvlnode * sups)383 dynlist_nested_memberOf( Entry *e, AttributeDescription *ad, TAvlnode *sups )
384 {
385 TAvlnode *ptr;
386 dynlist_name_t *dyn;
387 Attribute *a;
388
389 a = attr_find( e->e_attrs, ad );
390 for ( ptr = ldap_tavl_end( sups, TAVL_DIR_LEFT ); ptr;
391 ptr = ldap_tavl_next( ptr, TAVL_DIR_RIGHT )) {
392 dyn = ptr->avl_data;
393 if ( a ) {
394 unsigned slot;
395 if ( attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX |
396 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
397 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
398 &dyn->dy_name, &slot, NULL ) == LDAP_SUCCESS )
399 continue;
400 }
401 attr_merge_one( e, ad, &dyn->dy_name, &dyn->dy_name );
402 if ( !a )
403 a = attr_find( e->e_attrs, ad );
404 if ( dyn->dy_sups )
405 dynlist_nested_memberOf( e, ad, dyn->dy_sups );
406 }
407 }
408
409 typedef struct dynlist_member_t {
410 Entry *dm_e;
411 AttributeDescription *dm_ad;
412 Modification dm_mod;
413 TAvlnode *dm_groups;
414 struct berval dm_bv[2];
415 struct berval dm_nbv[2];
416 const char *dm_text;
417 char dm_textbuf[1024];
418 } dynlist_member_t;
419
420 static int
dynlist_ptr_cmp(const void * c1,const void * c2)421 dynlist_ptr_cmp( const void *c1, const void *c2 )
422 {
423 return ( c1 < c2 ) ? -1 : c1 > c2;
424 }
425
426 static int
dynlist_nested_member_dg(Operation * op,SlapReply * rs)427 dynlist_nested_member_dg( Operation *op, SlapReply *rs )
428 {
429 dynlist_member_t *dm = op->o_callback->sc_private;
430
431 if ( rs->sr_type != REP_SEARCH )
432 return LDAP_SUCCESS;
433
434 dm->dm_bv[0] = rs->sr_entry->e_name;
435 dm->dm_nbv[0] = rs->sr_entry->e_nname;
436 modify_add_values( dm->dm_e, &dm->dm_mod, /* permissive */ 1,
437 &dm->dm_text, dm->dm_textbuf, sizeof( dm->dm_textbuf ));
438
439 return LDAP_SUCCESS;
440 }
441
442 static void
dynlist_nested_member(Operation * op,dynlist_member_t * dm,TAvlnode * subs)443 dynlist_nested_member( Operation *op, dynlist_member_t *dm, TAvlnode *subs )
444 {
445 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
446 TAvlnode *ptr;
447 dynlist_name_t *dyn;
448 Entry *ne;
449 Attribute *a, *b;
450
451 a = attr_find( dm->dm_e->e_attrs, dm->dm_ad );
452 if ( !a )
453 return;
454
455 for ( ptr = ldap_tavl_end( subs, TAVL_DIR_LEFT ); ptr;
456 ptr = ldap_tavl_next( ptr, TAVL_DIR_RIGHT )) {
457 dyn = ptr->avl_data;
458 if ( ldap_tavl_insert( &dm->dm_groups, dyn, dynlist_ptr_cmp, ldap_avl_dup_error ))
459 continue;
460 if ( overlay_entry_get_ov( op, &dyn->dy_name, NULL, NULL, 0, &ne, on ) != LDAP_SUCCESS || ne == NULL )
461 continue;
462 b = attr_find( ne->e_attrs, dm->dm_ad );
463 if ( b ) {
464 dm->dm_mod.sm_values = b->a_vals;
465 dm->dm_mod.sm_nvalues = b->a_nvals;
466 dm->dm_mod.sm_numvals = b->a_numvals;
467 modify_add_values( dm->dm_e, &dm->dm_mod, /* permissive */ 1,
468 &dm->dm_text, dm->dm_textbuf, sizeof( dm->dm_textbuf ));
469 }
470 overlay_entry_release_ov( op, ne, 0, on );
471 if ( dyn->dy_numuris ) {
472 slap_callback cb = { 0 };
473 cb.sc_private = dm;
474 BER_BVZERO( &dm->dm_bv[1] );
475 BER_BVZERO( &dm->dm_nbv[1] );
476 dm->dm_mod.sm_values = dm->dm_bv;
477 dm->dm_mod.sm_nvalues = dm->dm_nbv;
478 dm->dm_mod.sm_numvals = 1;
479 cb.sc_response = dynlist_nested_member_dg;
480 dynlist_urlmembers( op, dyn, &cb );
481 }
482 if ( dyn->dy_subs )
483 dynlist_nested_member( op, dm, dyn->dy_subs );
484 }
485 }
486
487 static int
dynlist_prepare_entry(Operation * op,SlapReply * rs,dynlist_info_t * dli,dynlist_name_t * dyn)488 dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli, dynlist_name_t *dyn )
489 {
490 Attribute *a, *id = NULL;
491 slap_callback cb = { 0 };
492 Operation o = *op;
493 struct berval *url;
494 Entry *e;
495 int opattrs,
496 userattrs;
497 dynlist_sc_t dlc = { 0 };
498 dynlist_map_t *dlm;
499
500 e = rs->sr_entry;
501 a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad );
502 if ( a == NULL ) {
503 /* FIXME: error? */
504 goto checkdyn;
505 }
506
507 opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
508 userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
509
510 /* Don't generate member list if it wasn't requested */
511 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
512 AttributeDescription *ad = dlm->dlm_mapped_ad ? dlm->dlm_mapped_ad : dlm->dlm_member_ad;
513 if ( userattrs || ad_inlist( ad, rs->sr_attrs )
514 || ad_infilter( ad, op->ors_filter ))
515 break;
516 }
517 if ( dli->dli_dlm && !dlm )
518 goto checkdyn;
519
520 if ( ad_dgIdentity && ( id = attrs_find( rs->sr_entry->e_attrs, ad_dgIdentity ))) {
521 Attribute *authz = NULL;
522
523 /* if not rootdn and dgAuthz is present,
524 * check if user can be authorized as dgIdentity */
525 if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
526 && ( authz = attrs_find( rs->sr_entry->e_attrs, ad_dgAuthz ) ) )
527 {
528 if ( slap_sasl_matches( op, authz->a_nvals,
529 &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
530 {
531 goto checkdyn;
532 }
533 }
534
535 o.o_dn = id->a_vals[0];
536 o.o_ndn = id->a_nvals[0];
537 o.o_groups = NULL;
538 }
539
540 /* ensure e is modifiable, but do not replace
541 * sr_entry yet since we have pointers into it */
542 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
543 e = entry_dup( rs->sr_entry );
544 }
545
546 dlc.dlc_e = e;
547 dlc.dlc_dli = dli;
548 cb.sc_private = &dlc;
549 cb.sc_response = dynlist_sc_update;
550
551 o.o_callback = &cb;
552 o.ors_deref = LDAP_DEREF_NEVER;
553 o.ors_limit = NULL;
554 o.ors_tlimit = SLAP_NO_LIMIT;
555 o.ors_slimit = SLAP_NO_LIMIT;
556 memset( o.o_ctrlflag, 0, sizeof( o.o_ctrlflag ));
557
558 for ( url = a->a_nvals; !BER_BVISNULL( url ); url++ ) {
559 LDAPURLDesc *lud = NULL;
560 int i, j;
561 struct berval dn;
562 int rc;
563
564 BER_BVZERO( &o.o_req_dn );
565 BER_BVZERO( &o.o_req_ndn );
566 o.ors_filter = NULL;
567 o.ors_attrs = NULL;
568 BER_BVZERO( &o.ors_filterstr );
569
570 if ( ldap_url_parse( url->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
571 /* FIXME: error? */
572 continue;
573 }
574
575 if ( lud->lud_host != NULL ) {
576 /* FIXME: host not allowed; reject as illegal? */
577 Debug( LDAP_DEBUG_ANY, "dynlist_prepare_entry(\"%s\"): "
578 "illegal URI \"%s\"\n",
579 e->e_name.bv_val, url->bv_val );
580 goto cleanup;
581 }
582
583 if ( lud->lud_dn == NULL ) {
584 /* note that an empty base is not honored in terms
585 * of defaultSearchBase, because select_backend()
586 * is not aware of the defaultSearchBase option;
587 * this can be useful in case of a database serving
588 * the empty suffix */
589 BER_BVSTR( &dn, "" );
590
591 } else {
592 ber_str2bv( lud->lud_dn, 0, 0, &dn );
593 }
594 rc = dnPrettyNormal( NULL, &dn, &o.o_req_dn, &o.o_req_ndn, op->o_tmpmemctx );
595 if ( rc != LDAP_SUCCESS ) {
596 /* FIXME: error? */
597 goto cleanup;
598 }
599 o.ors_scope = lud->lud_scope;
600
601 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
602 if ( dlm->dlm_mapped_ad != NULL ) {
603 break;
604 }
605 }
606
607 if ( dli->dli_dlm && !dlm ) {
608 /* if ( lud->lud_attrs != NULL ),
609 * the URL should be ignored */
610 o.ors_attrs = slap_anlist_no_attrs;
611
612 } else if ( lud->lud_attrs == NULL ) {
613 o.ors_attrs = rs->sr_attrs;
614
615 } else {
616 for ( i = 0; lud->lud_attrs[i]; i++)
617 /* just count */ ;
618
619 o.ors_attrs = op->o_tmpcalloc( i + 1, sizeof( AttributeName ), op->o_tmpmemctx );
620 for ( i = 0, j = 0; lud->lud_attrs[i]; i++) {
621 const char *text = NULL;
622
623 ber_str2bv( lud->lud_attrs[i], 0, 0, &o.ors_attrs[j].an_name );
624 o.ors_attrs[j].an_desc = NULL;
625 (void)slap_bv2ad( &o.ors_attrs[j].an_name, &o.ors_attrs[j].an_desc, &text );
626 /* FIXME: ignore errors... */
627
628 if ( ad_infilter( o.ors_attrs[j].an_desc, op->ors_filter )) {
629 /* if referenced in filter, must retrieve */
630 } else if ( rs->sr_attrs == NULL ) {
631 if ( o.ors_attrs[j].an_desc != NULL &&
632 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
633 {
634 continue;
635 }
636
637 } else {
638 if ( o.ors_attrs[j].an_desc != NULL &&
639 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
640 {
641 if ( !opattrs ) {
642 continue;
643 }
644
645 if ( !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) ) {
646 /* lookup if mapped -- linear search,
647 * not very efficient unless list
648 * is very short */
649 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
650 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) {
651 break;
652 }
653 }
654
655 if ( dlm == NULL ) {
656 continue;
657 }
658 }
659
660 } else {
661 if ( !userattrs &&
662 o.ors_attrs[j].an_desc != NULL &&
663 !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
664 {
665 /* lookup if mapped -- linear search,
666 * not very efficient unless list
667 * is very short */
668 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
669 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) {
670 break;
671 }
672 }
673
674 if ( dlm == NULL ) {
675 continue;
676 }
677 }
678 }
679 }
680
681 j++;
682 }
683
684 if ( j == 0 ) {
685 goto cleanup;
686 }
687
688 BER_BVZERO( &o.ors_attrs[j].an_name );
689 }
690 dlc.dlc_attrs = lud->lud_attrs;
691
692 if ( lud->lud_filter == NULL ) {
693 ber_dupbv_x( &o.ors_filterstr,
694 &dli->dli_default_filter, op->o_tmpmemctx );
695
696 } else {
697 /* don't allow recursion in lists */
698 if ( lud->lud_attrs ) {
699 struct berval flt;
700 ber_str2bv( lud->lud_filter, 0, 0, &flt );
701 if ( dynlist_make_filter( op, rs->sr_entry, dli, url->bv_val, &flt, &o.ors_filterstr ) ) {
702 /* error */
703 goto cleanup;
704 }
705 } else {
706 ber_str2bv( lud->lud_filter, 0, 0, &o.ors_filterstr );
707 }
708 }
709 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
710 if ( o.ors_filter == NULL ) {
711 goto cleanup;
712 }
713
714 o.o_bd = select_backend( &o.o_req_ndn, 1 );
715 if ( o.o_bd && o.o_bd->be_search ) {
716 SlapReply r = { REP_SEARCH };
717 r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
718 o.o_managedsait = SLAP_CONTROL_CRITICAL;
719 (void)o.o_bd->be_search( &o, &r );
720 }
721
722 cleanup:;
723 if ( id ) {
724 slap_op_groups_free( &o );
725 }
726 if ( o.ors_filter ) {
727 filter_free_x( &o, o.ors_filter, 1 );
728 }
729 if ( o.ors_attrs && o.ors_attrs != rs->sr_attrs
730 && o.ors_attrs != slap_anlist_no_attrs )
731 {
732 op->o_tmpfree( o.ors_attrs, op->o_tmpmemctx );
733 }
734 if ( !BER_BVISNULL( &o.o_req_dn ) ) {
735 op->o_tmpfree( o.o_req_dn.bv_val, op->o_tmpmemctx );
736 }
737 if ( !BER_BVISNULL( &o.o_req_ndn ) ) {
738 op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx );
739 }
740 if ( lud->lud_attrs ) {
741 assert( BER_BVISNULL( &o.ors_filterstr )
742 || o.ors_filterstr.bv_val != lud->lud_filter );
743 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
744 } else {
745 if ( o.ors_filterstr.bv_val != lud->lud_filter )
746 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
747 }
748 ldap_free_urldesc( lud );
749 }
750
751 checkdyn:
752 /* handle nested groups */
753 if ( dyn && ( dyn->dy_sups || dyn->dy_subs )) {
754 /* ensure e is modifiable */
755 if ( e == rs->sr_entry && !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
756 e = entry_dup( rs->sr_entry );
757 rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e );
758 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
759 }
760 if ( dyn->dy_subs ) {
761 for ( dlm = dyn->dy_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
762 if ( dlm->dlm_member_ad ) {
763 dynlist_member_t dm;
764 dm.dm_groups = NULL;
765 dm.dm_mod.sm_op = LDAP_MOD_ADD;
766 dm.dm_mod.sm_desc = dlm->dlm_member_ad;
767 dm.dm_mod.sm_type = dlm->dlm_member_ad->ad_cname;
768 dm.dm_e = e;
769 dm.dm_ad = dlm->dlm_member_ad;
770 dynlist_nested_member( op, &dm, dyn->dy_subs );
771 if ( dm.dm_groups )
772 ldap_tavl_free( dm.dm_groups, NULL );
773 }
774 }
775 }
776 if ( dyn->dy_sups ) {
777 for ( dlm = dyn->dy_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
778 if ( dlm->dlm_memberOf_ad ) {
779 dynlist_nested_memberOf( e, dlm->dlm_memberOf_ad, dyn->dy_sups );
780 }
781 }
782 }
783 }
784
785 if ( e != rs->sr_entry ) {
786 rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e );
787 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
788 }
789
790 return SLAP_CB_CONTINUE;
791 }
792
793 /* dynlist_sc_compare_entry() callback set by dynlist_compare() */
794 typedef struct dynlist_cc_t {
795 slap_callback dc_cb;
796 # define dc_ava dc_cb.sc_private /* attr:val to compare with */
797 int *dc_res;
798 } dynlist_cc_t;
799
800 static int
dynlist_sc_compare_entry(Operation * op,SlapReply * rs)801 dynlist_sc_compare_entry( Operation *op, SlapReply *rs )
802 {
803 if ( rs->sr_type == REP_SEARCH && rs->sr_entry != NULL ) {
804 dynlist_cc_t *dc = (dynlist_cc_t *)op->o_callback;
805 AttributeAssertion *ava = dc->dc_ava;
806 Attribute *a = attrs_find( rs->sr_entry->e_attrs, ava->aa_desc );
807
808 if ( a != NULL ) {
809 while ( LDAP_SUCCESS != attr_valfind( a,
810 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
811 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
812 &ava->aa_value, NULL, op->o_tmpmemctx )
813 && (a = attrs_find( a->a_next, ava->aa_desc )) != NULL )
814 ;
815 *dc->dc_res = a ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
816 }
817 }
818
819 return 0;
820 }
821
822 static int
dynlist_compare(Operation * op,SlapReply * rs)823 dynlist_compare( Operation *op, SlapReply *rs )
824 {
825 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
826 dynlist_gen_t *dlg = (dynlist_gen_t *)on->on_bi.bi_private;
827 dynlist_info_t *dli = dlg->dlg_dli;
828 Operation o = *op;
829 Entry *e = NULL;
830 dynlist_map_t *dlm;
831 BackendDB *be;
832 int ret = SLAP_CB_CONTINUE;
833
834 if ( get_manageDSAit( op ) )
835 return SLAP_CB_CONTINUE;
836
837 for ( ; dli != NULL; dli = dli->dli_next ) {
838 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
839 AttributeDescription *ad = dlm->dlm_mapped_ad ? dlm->dlm_mapped_ad : dlm->dlm_member_ad;
840 /* builtin dyngroup evaluator only works for DNs */
841 if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName )
842 continue;
843 if ( op->oq_compare.rs_ava->aa_desc == ad )
844 break;
845 }
846
847 if ( dlm ) {
848 /* This compare is for one of the attributes we're
849 * interested in. We'll use slapd's existing dyngroup
850 * evaluator to get the answer we want.
851 */
852 BerVarray id = NULL, authz = NULL;
853
854 o.o_do_not_cache = 1;
855
856 if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn,
857 ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS )
858 {
859 /* if not rootdn and dgAuthz is present,
860 * check if user can be authorized as dgIdentity */
861 if ( ad_dgAuthz && !BER_BVISEMPTY( id ) && !be_isroot( op )
862 && backend_attribute( &o, NULL, &o.o_req_ndn,
863 ad_dgAuthz, &authz, ACL_READ ) == LDAP_SUCCESS )
864 {
865
866 rs->sr_err = slap_sasl_matches( op, authz,
867 &o.o_ndn, &o.o_ndn );
868 ber_bvarray_free_x( authz, op->o_tmpmemctx );
869 if ( rs->sr_err != LDAP_SUCCESS ) {
870 goto done;
871 }
872 }
873
874 o.o_dn = *id;
875 o.o_ndn = *id;
876 o.o_groups = NULL; /* authz changed, invalidate cached groups */
877 }
878
879 rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn,
880 &o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad );
881 switch ( rs->sr_err ) {
882 case LDAP_SUCCESS:
883 rs->sr_err = LDAP_COMPARE_TRUE;
884 break;
885
886 case LDAP_NO_SUCH_OBJECT:
887 /* NOTE: backend_group() returns noSuchObject
888 * if op_ndn does not exist; however, since
889 * dynamic list expansion means that the
890 * member attribute is virtually present, the
891 * non-existence of the asserted value implies
892 * the assertion is FALSE rather than
893 * UNDEFINED */
894 rs->sr_err = LDAP_COMPARE_FALSE;
895 break;
896 }
897
898 done:;
899 if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx );
900
901 send_ldap_result( op, rs );
902 return rs->sr_err;
903 }
904 }
905
906 be = select_backend( &o.o_req_ndn, 1 );
907 if ( !be || !be->be_search ) {
908 return SLAP_CB_CONTINUE;
909 }
910
911 if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) !=
912 LDAP_SUCCESS || e == NULL )
913 {
914 return SLAP_CB_CONTINUE;
915 }
916
917 /* check for dynlist objectClass; done if not found */
918 dli = (dynlist_info_t *)dlg->dlg_dli;
919 while ( dli != NULL && !is_entry_objectclass_or_sub( e, dli->dli_oc ) ) {
920 dli = dli->dli_next;
921 }
922 if ( dli == NULL ) {
923 goto release;
924 }
925
926 if ( ad_dgIdentity ) {
927 Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity );
928 if ( id ) {
929 Attribute *authz;
930
931 /* if not rootdn and dgAuthz is present,
932 * check if user can be authorized as dgIdentity */
933 if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
934 && ( authz = attrs_find( e->e_attrs, ad_dgAuthz ) ) )
935 {
936 if ( slap_sasl_matches( op, authz->a_nvals,
937 &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
938 {
939 goto release;
940 }
941 }
942
943 o.o_dn = id->a_vals[0];
944 o.o_ndn = id->a_nvals[0];
945 o.o_groups = NULL;
946 }
947 }
948
949 /* generate dynamic list with dynlist_response() and compare */
950 {
951 SlapReply r = { REP_SEARCH };
952 Attribute *a;
953 AttributeName an[2];
954
955 o.o_tag = LDAP_REQ_SEARCH;
956 o.ors_limit = NULL;
957 o.ors_tlimit = SLAP_NO_LIMIT;
958 o.ors_slimit = SLAP_NO_LIMIT;
959
960 o.ors_filterstr = *slap_filterstr_objectClass_pres;
961 o.ors_filter = (Filter *) slap_filter_objectClass_pres;
962
963 o.ors_scope = LDAP_SCOPE_BASE;
964 o.ors_deref = LDAP_DEREF_NEVER;
965 an[0].an_name = op->orc_ava->aa_desc->ad_cname;
966 an[0].an_desc = op->orc_ava->aa_desc;
967 BER_BVZERO( &an[1].an_name );
968 o.ors_attrs = an;
969 o.ors_attrsonly = 0;
970 r.sr_entry = e;
971 r.sr_attrs = an;
972
973 o.o_acl_priv = ACL_COMPARE;
974 dynlist_prepare_entry( &o, &r, dli, NULL );
975 a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
976
977 ret = LDAP_NO_SUCH_ATTRIBUTE;
978 for ( ; a ; a = attrs_find( a->a_next, op->orc_ava->aa_desc )) {
979 ret = LDAP_COMPARE_FALSE;
980 if ( attr_valfind( a,
981 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
982 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
983 &op->orc_ava->aa_value, NULL, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
984 ret = LDAP_COMPARE_TRUE;
985 break;
986 }
987 }
988 rs->sr_err = ret;
989
990 if ( r.sr_entry != e )
991 entry_free( r.sr_entry );
992 send_ldap_result( op, rs );
993 }
994
995 release:;
996 if ( e != NULL ) {
997 overlay_entry_release_ov( &o, e, 0, on );
998 }
999
1000 return ret;
1001 }
1002
1003 #define WANT_MEMBEROF 1
1004 #define WANT_MEMBER 2
1005
1006 typedef struct dynlist_search_t {
1007 TAvlnode *ds_names;
1008 TAvlnode *ds_fnodes;
1009 dynlist_info_t *ds_dli;
1010 dynlist_map_t *ds_dlm;
1011 Filter *ds_origfilter;
1012 struct berval ds_origfilterbv;
1013 int ds_want;
1014 int ds_found;
1015 } dynlist_search_t;
1016
1017 static int
dynlist_avl_cmp(const void * c1,const void * c2)1018 dynlist_avl_cmp( const void *c1, const void *c2 )
1019 {
1020 const dynlist_name_t *n1, *n2;
1021 int rc;
1022 n1 = c1; n2 = c2;
1023
1024 rc = n1->dy_name.bv_len - n2->dy_name.bv_len;
1025 if ( rc ) return rc;
1026 return ber_bvcmp( &n1->dy_name, &n2->dy_name );
1027 }
1028
1029 /* build a list of dynamic entries */
1030 static int
dynlist_search1resp(Operation * op,SlapReply * rs)1031 dynlist_search1resp( Operation *op, SlapReply *rs )
1032 {
1033 if ( rs->sr_type == REP_SEARCH && rs->sr_entry != NULL ) {
1034 dynlist_search_t *ds = op->o_callback->sc_private;
1035 Attribute *a, *b = NULL;
1036
1037 if ( ds->ds_dlm && ds->ds_dlm->dlm_static_oc && is_entry_objectclass( rs->sr_entry, ds->ds_dlm->dlm_static_oc, 0 ))
1038 b = attr_find( rs->sr_entry->e_attrs, ds->ds_dlm->dlm_member_ad );
1039 a = attr_find( rs->sr_entry->e_attrs, ds->ds_dli->dli_ad );
1040 if ( a || b ) {
1041 unsigned len;
1042 dynlist_name_t *dyn;
1043 struct berval bv, nbase;
1044 LDAPURLDesc *ludp;
1045 int i, j = 0;
1046
1047 if ( a )
1048 len = a->a_numvals * sizeof(LDAPURLDesc *);
1049 else
1050 len = 0;
1051
1052 dyn = ch_calloc(1, sizeof(dynlist_name_t)+rs->sr_entry->e_nname.bv_len + 1 + len);
1053 dyn->dy_name.bv_val = ((char *)(dyn+1)) + len;
1054 dyn->dy_dli = ds->ds_dli;
1055 dyn->dy_name.bv_len = rs->sr_entry->e_nname.bv_len;
1056 if ( a ) {
1057 Filter *f;
1058 /* parse and validate the URIs */
1059 for (i=0; i<a->a_numvals; i++) {
1060 if (ldap_url_parse( a->a_vals[i].bv_val, &ludp ) != LDAP_URL_SUCCESS )
1061 continue;
1062 if (( ludp->lud_host && *ludp->lud_host)
1063 || ludp->lud_exts ) {
1064 skipit:
1065 ldap_free_urldesc( ludp );
1066 continue;
1067 }
1068 ber_str2bv( ludp->lud_dn, 0, 0, &bv );
1069 if ( dnNormalize( 0, NULL, NULL, &bv, &nbase, op->o_tmpmemctx ) != LDAP_SUCCESS )
1070 goto skipit;
1071 ldap_memfree( ludp->lud_dn );
1072 ludp->lud_dn = ldap_strdup( nbase.bv_val );
1073 op->o_tmpfree( nbase.bv_val, op->o_tmpmemctx );
1074 /* cheat here, reuse fields */
1075 ludp->lud_port = nbase.bv_len;
1076 if ( ludp->lud_filter && *ludp->lud_filter ) {
1077 f = str2filter( ludp->lud_filter );
1078 if ( f == NULL )
1079 goto skipit;
1080 ldap_memfree( ludp->lud_filter );
1081 } else {
1082 f = ch_malloc( sizeof( Filter ));
1083 f->f_choice = SLAPD_FILTER_COMPUTED;
1084 f->f_result = LDAP_COMPARE_TRUE;
1085 f->f_next = NULL;
1086 }
1087 ludp->lud_filter = (char *)f;
1088 dyn->dy_uris[j] = ludp;
1089 j++;
1090 }
1091 }
1092 dyn->dy_numuris = j;
1093 memcpy(dyn->dy_name.bv_val, rs->sr_entry->e_nname.bv_val, rs->sr_entry->e_nname.bv_len );
1094 if ( b )
1095 dyn->dy_staticmember = ds->ds_dlm->dlm_member_ad;
1096
1097 if ( ldap_tavl_insert( &ds->ds_names, dyn, dynlist_avl_cmp, ldap_avl_dup_error )) {
1098 for (i=dyn->dy_numuris-1; i>=0; i--) {
1099 ludp = dyn->dy_uris[i];
1100 if ( ludp->lud_filter ) {
1101 filter_free( (Filter *)ludp->lud_filter );
1102 ludp->lud_filter = NULL;
1103 }
1104 ldap_free_urldesc( ludp );
1105 }
1106 ch_free( dyn );
1107 } else {
1108 ds->ds_found++;
1109 }
1110 }
1111 }
1112 return 0;
1113 }
1114
1115 /* replace a filter clause (memberOf=<groupDN>) with an expansion
1116 * of its dynamic members
1117 * using (&(entryDN=<groupURIbase>)<groupURIfilter>)
1118 */
1119 static int
dynlist_filter_dyngroup(Operation * op,Filter * n,Attribute * a)1120 dynlist_filter_dyngroup( Operation *op, Filter *n, Attribute *a )
1121 {
1122 Filter *andf = NULL, *dnf, *urif, *orf = NULL;
1123 LDAPURLDesc *ludp;
1124 struct berval bv, nbase;
1125 int i;
1126
1127 for (i=0; i<a->a_numvals; i++) {
1128 if ( ldap_url_parse( a->a_vals[i].bv_val, &ludp ) != LDAP_URL_SUCCESS )
1129 continue;
1130 if (( ludp->lud_host && *ludp->lud_host )
1131 || ludp->lud_attrs
1132 || ludp->lud_exts ) {
1133 skip:
1134 ldap_free_urldesc( ludp );
1135 continue;
1136 }
1137 ber_str2bv( ludp->lud_dn, 0, 0, &bv );
1138 if ( dnNormalize( 0, NULL, NULL, &bv, &nbase, op->o_tmpmemctx ) != LDAP_SUCCESS )
1139 goto skip;
1140 if ( ludp->lud_filter && *ludp->lud_filter ) {
1141 urif = str2filter_x( op, ludp->lud_filter );
1142 if ( urif == NULL ) {
1143 op->o_tmpfree( nbase.bv_val, op->o_tmpmemctx );
1144 goto skip;
1145 }
1146 } else {
1147 urif = NULL;
1148 }
1149 if ( !andf && n->f_choice == SLAPD_FILTER_COMPUTED ) {
1150 andf = n;
1151 andf->f_next = NULL;
1152 } else {
1153 orf = n;
1154 if ( n->f_choice != LDAP_FILTER_OR ) {
1155 andf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
1156 *andf = *n;
1157 orf->f_choice = LDAP_FILTER_OR;
1158 orf->f_next = NULL;
1159 orf->f_list = andf;
1160 }
1161 andf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
1162 andf->f_next = orf->f_list;
1163 orf->f_list = andf;
1164 }
1165 dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
1166 andf->f_choice = LDAP_FILTER_AND;
1167 andf->f_list = dnf;
1168 dnf->f_next = urif;
1169 if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
1170 dnf->f_choice = LDAP_FILTER_EQUALITY;
1171 dnf->f_ava = op->o_tmpcalloc( 1, sizeof(AttributeAssertion), op->o_tmpmemctx );
1172 dnf->f_av_desc = slap_schema.si_ad_entryDN;
1173 dnf->f_av_value = nbase;
1174 } else {
1175 dnf->f_choice = LDAP_FILTER_EXT;
1176 dnf->f_mra = op->o_tmpcalloc( 1, sizeof(MatchingRuleAssertion), op->o_tmpmemctx );
1177 dnf->f_mr_desc = slap_schema.si_ad_entryDN;
1178 dnf->f_mr_value = nbase;
1179 switch ( ludp->lud_scope ) {
1180 case LDAP_SCOPE_ONELEVEL:
1181 dnf->f_mr_rule = slap_schema.si_mr_dnOneLevelMatch;
1182 break;
1183 case LDAP_SCOPE_SUBTREE:
1184 dnf->f_mr_rule = slap_schema.si_mr_dnSubtreeMatch;
1185 break;
1186 case LDAP_SCOPE_SUBORDINATE:
1187 dnf->f_mr_rule = slap_schema.si_mr_dnSubordinateMatch;
1188 break;
1189 }
1190 ber_str2bv( dnf->f_mr_rule->smr_names[0], 0, 0, &dnf->f_mr_rule_text );
1191 }
1192 ldap_free_urldesc( ludp );
1193 }
1194 if ( !andf )
1195 return -1;
1196 return 0;
1197 }
1198
1199 /* replace a filter clause (memberOf=<groupDN>) with an expansion
1200 * of its static members
1201 * using (|(entryDN=<memberN>)[...])
1202 */
1203 static int
dynlist_filter_stgroup(Operation * op,Filter * n,Attribute * a)1204 dynlist_filter_stgroup( Operation *op, Filter *n, Attribute *a )
1205 {
1206 Filter *dnf, *orf = NULL;
1207 int i;
1208
1209 if ( a->a_numvals == 1 && n->f_choice == SLAPD_FILTER_COMPUTED ) {
1210 dnf = n;
1211 dnf->f_next = NULL;
1212 } else {
1213 orf = n;
1214 if ( n->f_choice != LDAP_FILTER_OR ) {
1215 dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
1216 *dnf = *n;
1217 orf->f_choice = LDAP_FILTER_OR;
1218 orf->f_next = NULL;
1219 orf->f_list = dnf;
1220 }
1221 dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
1222 dnf->f_next = orf->f_list;
1223 orf->f_list = dnf;
1224 }
1225
1226 for (i=0; i<a->a_numvals; i++) {
1227 if ( i ) {
1228 dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
1229 dnf->f_next = orf->f_list;
1230 orf->f_list = dnf;
1231 }
1232 dnf->f_choice = LDAP_FILTER_EQUALITY;
1233 dnf->f_ava = op->o_tmpcalloc( 1, sizeof(AttributeAssertion), op->o_tmpmemctx );
1234 dnf->f_av_desc = slap_schema.si_ad_entryDN;
1235 ber_dupbv_x( &dnf->f_av_value, &a->a_nvals[i], op->o_tmpmemctx );
1236 }
1237 return 0;
1238 }
1239
1240 /* replace a filter clause (memberOf=<groupDN>) with an expansion of
1241 * its members.
1242 */
1243 static int
dynlist_filter_group(Operation * op,dynlist_name_t * dyn,Filter * n,dynlist_search_t * ds)1244 dynlist_filter_group( Operation *op, dynlist_name_t *dyn, Filter *n, dynlist_search_t *ds )
1245 {
1246 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1247 Entry *e;
1248 Attribute *a;
1249 int rc = -1;
1250
1251 if ( ldap_tavl_insert( &ds->ds_fnodes, dyn, dynlist_ptr_cmp, ldap_avl_dup_error ))
1252 return 0;
1253
1254 if ( overlay_entry_get_ov( op, &dyn->dy_name, NULL, NULL, 0, &e, on ) !=
1255 LDAP_SUCCESS || e == NULL ) {
1256 return -1;
1257 }
1258 if ( ds->ds_dlm->dlm_static_oc && is_entry_objectclass( e, ds->ds_dlm->dlm_static_oc, 0 )) {
1259 a = attr_find( e->e_attrs, ds->ds_dlm->dlm_member_ad );
1260 if ( a ) {
1261 rc = dynlist_filter_stgroup( op, n, a );
1262 }
1263 } else {
1264 a = attr_find( e->e_attrs, ds->ds_dli->dli_ad );
1265 if ( a ) {
1266 rc = dynlist_filter_dyngroup( op, n, a );
1267 }
1268 }
1269 overlay_entry_release_ov( op, e, 0, on );
1270 if ( dyn->dy_subs && !rc ) {
1271 TAvlnode *ptr;
1272 for ( ptr = ldap_tavl_end( dyn->dy_subs, TAVL_DIR_LEFT ); ptr;
1273 ptr = ldap_tavl_next( ptr, TAVL_DIR_RIGHT )) {
1274 dyn = ptr->avl_data;
1275 rc = dynlist_filter_group( op, dyn, n, ds );
1276 if ( rc )
1277 break;
1278 }
1279 }
1280 return rc;
1281 }
1282
1283 /* Dup the filter, replacing any references to given ad with group evaluation */
1284 static Filter *
dynlist_filter_dup(Operation * op,Filter * f,AttributeDescription * ad,dynlist_search_t * ds)1285 dynlist_filter_dup( Operation *op, Filter *f, AttributeDescription *ad, dynlist_search_t *ds )
1286 {
1287 Filter *n = NULL;
1288
1289 if ( !f )
1290 return NULL;
1291
1292 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
1293 n->f_next = NULL;
1294 switch( f->f_choice & SLAPD_FILTER_MASK ) {
1295 case SLAPD_FILTER_COMPUTED:
1296 n->f_choice = f->f_choice;
1297 n->f_result = f->f_result;
1298 break;
1299
1300 case LDAP_FILTER_PRESENT:
1301 n->f_choice = f->f_choice;
1302 n->f_desc = f->f_desc;
1303 break;
1304
1305 case LDAP_FILTER_EQUALITY:
1306 n->f_choice = SLAPD_FILTER_COMPUTED;
1307 if ( f->f_av_desc == ad ) {
1308 dynlist_name_t *dyn = ldap_tavl_find( ds->ds_names, &f->f_av_value, dynlist_avl_cmp );
1309 if ( dyn && !dynlist_filter_group( op, dyn, n, ds ))
1310 break;
1311 }
1312 /* FALLTHRU */
1313 case LDAP_FILTER_GE:
1314 case LDAP_FILTER_LE:
1315 case LDAP_FILTER_APPROX:
1316 n->f_choice = f->f_choice;
1317 n->f_ava = f->f_ava;
1318 break;
1319
1320 case LDAP_FILTER_SUBSTRINGS:
1321 n->f_choice = f->f_choice;
1322 n->f_sub = f->f_sub;
1323 break;
1324
1325 case LDAP_FILTER_EXT:
1326 n->f_choice = f->f_choice;
1327 n->f_mra = f->f_mra;
1328 break;
1329
1330 case LDAP_FILTER_NOT:
1331 case LDAP_FILTER_AND:
1332 case LDAP_FILTER_OR: {
1333 Filter **p;
1334
1335 n->f_choice = f->f_choice;
1336
1337 for ( p = &n->f_list, f = f->f_list; f; f = f->f_next ) {
1338 *p = dynlist_filter_dup( op, f, ad, ds );
1339 if ( !*p )
1340 continue;
1341 p = &(*p)->f_next;
1342 }
1343 }
1344 break;
1345 }
1346 return n;
1347 }
1348
1349 static void
dynlist_filter_free(Operation * op,Filter * f)1350 dynlist_filter_free( Operation *op, Filter *f )
1351 {
1352 Filter *p, *next;
1353
1354 if ( f == NULL )
1355 return;
1356
1357 f->f_choice &= SLAPD_FILTER_MASK;
1358 switch( f->f_choice ) {
1359 case LDAP_FILTER_AND:
1360 case LDAP_FILTER_OR:
1361 case LDAP_FILTER_NOT:
1362 for ( p = f->f_list; p; p = next ) {
1363 next = p->f_next;
1364 op->o_tmpfree( p, op->o_tmpmemctx );
1365 }
1366 break;
1367 default:
1368 op->o_tmpfree( f, op->o_tmpmemctx );
1369 }
1370 }
1371
1372 static void
dynlist_search_free(void * ptr)1373 dynlist_search_free( void *ptr )
1374 {
1375 dynlist_name_t *dyn = (dynlist_name_t *)ptr;
1376 LDAPURLDesc *ludp;
1377 int i;
1378
1379 for (i=dyn->dy_numuris-1; i>=0; i--) {
1380 ludp = dyn->dy_uris[i];
1381 if ( ludp->lud_filter ) {
1382 filter_free( (Filter *)ludp->lud_filter );
1383 ludp->lud_filter = NULL;
1384 }
1385 ldap_free_urldesc( ludp );
1386 }
1387 if ( dyn->dy_subs )
1388 ldap_tavl_free( dyn->dy_subs, NULL );
1389 if ( dyn->dy_sups )
1390 ldap_tavl_free( dyn->dy_sups, NULL );
1391 ch_free( ptr );
1392 }
1393
1394 static int
dynlist_search_cleanup(Operation * op,SlapReply * rs)1395 dynlist_search_cleanup( Operation *op, SlapReply *rs )
1396 {
1397 if ( rs->sr_type == REP_RESULT || op->o_abandon ||
1398 rs->sr_err == SLAPD_ABANDON ) {
1399 slap_callback *sc = op->o_callback;
1400 dynlist_search_t *ds = op->o_callback->sc_private;
1401 ldap_tavl_free( ds->ds_names, dynlist_search_free );
1402 if ( ds->ds_fnodes )
1403 ldap_tavl_free( ds->ds_fnodes, NULL );
1404 if ( ds->ds_origfilter ) {
1405 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1406 dynlist_filter_free( op, op->ors_filter );
1407 op->ors_filter = ds->ds_origfilter;
1408 op->ors_filterstr = ds->ds_origfilterbv;
1409 }
1410 op->o_callback = sc->sc_next;
1411 op->o_tmpfree( sc, op->o_tmpmemctx );
1412
1413 }
1414 return 0;
1415 }
1416
1417 static int
dynlist_test_membership(Operation * op,dynlist_name_t * dyn,Entry * e)1418 dynlist_test_membership(Operation *op, dynlist_name_t *dyn, Entry *e)
1419 {
1420 LDAPURLDesc *ludp;
1421 struct berval nbase, bv;
1422 int i, rc = LDAP_COMPARE_FALSE;
1423 if ( dyn->dy_staticmember ) {
1424 Entry *grp;
1425 if ( overlay_entry_get_ov( op, &dyn->dy_name, NULL, NULL, 0, &grp, (slap_overinst *)op->o_bd->bd_info ) == LDAP_SUCCESS && grp ) {
1426 Attribute *a = attr_find( grp->e_attrs, dyn->dy_staticmember );
1427 if ( a ) {
1428 i = value_find_ex( dyn->dy_staticmember, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1429 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a->a_nvals, &e->e_nname, op->o_tmpmemctx );
1430 }
1431 overlay_entry_release_ov( op, grp, 0, (slap_overinst *)op->o_bd->bd_info );
1432 return i == LDAP_SUCCESS ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
1433 }
1434 }
1435 for (i=0; i<dyn->dy_numuris; i++) {
1436 ludp = dyn->dy_uris[i];
1437 nbase.bv_val = ludp->lud_dn;
1438 nbase.bv_len = ludp->lud_port;
1439 if ( ludp->lud_attrs )
1440 continue;
1441 switch( ludp->lud_scope ) {
1442 case LDAP_SCOPE_BASE:
1443 if ( !dn_match( &nbase, &e->e_nname ))
1444 continue;
1445 break;
1446 case LDAP_SCOPE_ONELEVEL:
1447 dnParent( &e->e_nname, &bv );
1448 if ( !dn_match( &nbase, &bv ))
1449 continue;
1450 break;
1451 case LDAP_SCOPE_SUBTREE:
1452 if ( !dnIsSuffix( &e->e_nname, &nbase ))
1453 continue;
1454 break;
1455 case LDAP_SCOPE_SUBORDINATE:
1456 if ( dn_match( &nbase, &e->e_nname ) ||
1457 !dnIsSuffix( &e->e_nname, &nbase ))
1458 continue;
1459 break;
1460 }
1461 if ( !ludp->lud_filter ) /* there really should always be a filter */
1462 rc = LDAP_COMPARE_TRUE;
1463 else
1464 rc = test_filter( op, e, (Filter *)ludp->lud_filter );
1465 if ( rc == LDAP_COMPARE_TRUE )
1466 break;
1467 }
1468 return rc;
1469 }
1470
1471 static void
dynlist_add_memberOf(Operation * op,SlapReply * rs,dynlist_search_t * ds)1472 dynlist_add_memberOf(Operation *op, SlapReply *rs, dynlist_search_t *ds)
1473 {
1474 TAvlnode *ptr;
1475 Entry *e = rs->sr_entry;
1476 dynlist_name_t *dyn;
1477 Attribute *a;
1478
1479 /* See if there are any memberOf values to attach to this entry */
1480 for ( ptr = ldap_tavl_end( ds->ds_names, TAVL_DIR_LEFT ); ptr;
1481 ptr = ldap_tavl_next( ptr, TAVL_DIR_RIGHT )) {
1482 dynlist_map_t *dlm;
1483 dyn = ptr->avl_data;
1484 for ( dlm = dyn->dy_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
1485 if ( dlm->dlm_memberOf_ad ) {
1486 if ( dynlist_test_membership( op, dyn, e ) == LDAP_COMPARE_TRUE ) {
1487 /* ensure e is modifiable, but do not replace
1488 * sr_entry yet since we have pointers into it */
1489 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) && e == rs->sr_entry ) {
1490 e = entry_dup( rs->sr_entry );
1491 }
1492 a = attr_find( e->e_attrs, dlm->dlm_memberOf_ad );
1493 if ( a ) {
1494 unsigned slot;
1495 if ( attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX |
1496 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
1497 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
1498 &dyn->dy_name, &slot, NULL ) != LDAP_SUCCESS )
1499 a = NULL;
1500 }
1501 if ( !a )
1502 attr_merge_one( e, dlm->dlm_memberOf_ad, &dyn->dy_name, &dyn->dy_name );
1503 if ( dyn->dy_sups ) {
1504 dynlist_nested_memberOf( e, dlm->dlm_memberOf_ad, dyn->dy_sups );
1505 }
1506 break;
1507 }
1508 }
1509 }
1510 }
1511 if ( e != rs->sr_entry ) {
1512 rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e );
1513 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
1514 }
1515 }
1516
1517 /* process the search responses */
1518 static int
dynlist_search2resp(Operation * op,SlapReply * rs)1519 dynlist_search2resp( Operation *op, SlapReply *rs )
1520 {
1521 dynlist_search_t *ds = op->o_callback->sc_private;
1522 dynlist_name_t *dyn;
1523 int rc;
1524
1525 if ( rs->sr_type == REP_SEARCH && rs->sr_entry != NULL ) {
1526 rc = SLAP_CB_CONTINUE;
1527 /* See if this is one of our dynamic entries */
1528 dyn = ldap_tavl_find( ds->ds_names, &rs->sr_entry->e_nname, dynlist_avl_cmp );
1529 if ( dyn ) {
1530 dyn->dy_seen = 1;
1531 rc = dynlist_prepare_entry( op, rs, dyn->dy_dli, dyn );
1532 } else if ( ds->ds_want )
1533 dynlist_add_memberOf( op, rs, ds );
1534 if ( ds->ds_origfilter && test_filter( op, rs->sr_entry, ds->ds_origfilter ) != LDAP_COMPARE_TRUE ) {
1535 rs_flush_entry( op, rs, NULL );
1536 return LDAP_SUCCESS;
1537 }
1538 return rc;
1539 } else if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS ) {
1540 TAvlnode *ptr;
1541 SlapReply r = *rs;
1542 Filter *f = ds->ds_origfilter ? ds->ds_origfilter : op->ors_filter;
1543
1544 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED )
1545 return SLAP_CB_CONTINUE;
1546
1547 /* Check for any unexpanded dynamic group entries that weren't picked up
1548 * by the original search filter.
1549 */
1550 for ( ptr = ldap_tavl_end( ds->ds_names, TAVL_DIR_LEFT ); ptr;
1551 ptr = ldap_tavl_next( ptr, TAVL_DIR_RIGHT )) {
1552 dyn = ptr->avl_data;
1553 if ( dyn->dy_seen )
1554 continue;
1555 if ( !dnIsSuffixScope( &dyn->dy_name, &op->o_req_ndn, op->ors_scope ))
1556 continue;
1557 if ( overlay_entry_get_ov( op, &dyn->dy_name, NULL, NULL, 0, &r.sr_entry, (slap_overinst *)op->o_bd->bd_info ) != LDAP_SUCCESS ||
1558 r.sr_entry == NULL )
1559 continue;
1560 r.sr_flags = REP_ENTRY_MUSTRELEASE;
1561 dynlist_prepare_entry( op, &r, dyn->dy_dli, dyn );
1562 if ( test_filter( op, r.sr_entry, f ) == LDAP_COMPARE_TRUE ) {
1563 r.sr_attrs = op->ors_attrs;
1564 rs->sr_err = send_search_entry( op, &r );
1565 if ( rs->sr_err != LDAP_SUCCESS )
1566 break;
1567 } else {
1568 rs_flush_entry( op, &r, NULL );
1569 }
1570 }
1571 rs->sr_nentries = r.sr_nentries;
1572 }
1573 return SLAP_CB_CONTINUE;
1574 }
1575
1576 static void
dynlist_fix_filter(Operation * op,AttributeDescription * ad,dynlist_search_t * ds)1577 dynlist_fix_filter( Operation *op, AttributeDescription *ad, dynlist_search_t *ds )
1578 {
1579 Filter *f;
1580 f = dynlist_filter_dup( op, op->ors_filter, ad, ds );
1581 if ( ds->ds_origfilter ) {
1582 dynlist_filter_free( op, op->ors_filter );
1583 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1584 } else {
1585 ds->ds_origfilter = op->ors_filter;
1586 ds->ds_origfilterbv = op->ors_filterstr;
1587 }
1588 op->ors_filter = f;
1589 filter2bv_x( op, f, &op->ors_filterstr );
1590 }
1591
1592 typedef struct dynlist_link_t {
1593 dynlist_search_t *dl_ds;
1594 dynlist_name_t *dl_sup;
1595 } dynlist_link_t;
1596
1597 static int
dynlist_nestlink_dg(Operation * op,SlapReply * rs)1598 dynlist_nestlink_dg( Operation *op, SlapReply *rs )
1599 {
1600 dynlist_link_t *dll = op->o_callback->sc_private;
1601 dynlist_search_t *ds = dll->dl_ds;
1602 dynlist_name_t *di = dll->dl_sup, *dj;
1603
1604 if ( rs->sr_type != REP_SEARCH )
1605 return LDAP_SUCCESS;
1606
1607 dj = ldap_tavl_find( dll->dl_ds->ds_names, &rs->sr_entry->e_nname, dynlist_avl_cmp );
1608 if ( dj ) {
1609 if ( ds->ds_want & WANT_MEMBEROF ) {
1610 ldap_tavl_insert( &dj->dy_sups, di, dynlist_ptr_cmp, ldap_avl_dup_error );
1611 }
1612 if ( ds->ds_want & WANT_MEMBER ) {
1613 ldap_tavl_insert( &di->dy_subs, dj, dynlist_ptr_cmp, ldap_avl_dup_error );
1614 }
1615 }
1616 return LDAP_SUCCESS;
1617 }
1618
1619 /* Connect all nested groups to their parents/children */
1620 static void
dynlist_nestlink(Operation * op,dynlist_search_t * ds)1621 dynlist_nestlink( Operation *op, dynlist_search_t *ds )
1622 {
1623 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1624 dynlist_name_t *di, *dj;
1625 TAvlnode *ptr;
1626 Entry *e;
1627 Attribute *a;
1628 int i;
1629
1630 for ( ptr = ldap_tavl_end( ds->ds_names, TAVL_DIR_LEFT ); ptr;
1631 ptr = ldap_tavl_next( ptr, TAVL_DIR_RIGHT )) {
1632 di = ptr->avl_data;
1633 if ( ds->ds_dlm ) {
1634 if ( overlay_entry_get_ov( op, &di->dy_name, NULL, NULL, 0, &e, on ) != LDAP_SUCCESS || e == NULL )
1635 continue;
1636 a = attr_find( e->e_attrs, ds->ds_dlm->dlm_member_ad );
1637 if ( a ) {
1638 for ( i=0; i < a->a_numvals; i++ ) {
1639 dj = ldap_tavl_find( ds->ds_names, &a->a_nvals[i], dynlist_avl_cmp );
1640 if ( dj ) {
1641 if ( ds->ds_want & WANT_MEMBEROF ) {
1642 ldap_tavl_insert( &dj->dy_sups, di, dynlist_ptr_cmp, ldap_avl_dup_error );
1643 }
1644 if ( ds->ds_want & WANT_MEMBER ) {
1645 ldap_tavl_insert( &di->dy_subs, dj, dynlist_ptr_cmp, ldap_avl_dup_error );
1646 }
1647 }
1648 }
1649 }
1650 overlay_entry_release_ov( op, e, 0, on );
1651 }
1652
1653 if ( di->dy_numuris ) {
1654 slap_callback cb = { 0 };
1655 dynlist_link_t dll;
1656 dll.dl_ds = ds;
1657 dll.dl_sup = di;
1658 cb.sc_private = &dll;
1659 cb.sc_response = dynlist_nestlink_dg;
1660 dynlist_urlmembers( op, di, &cb );
1661 }
1662 }
1663 }
1664
1665 static int
dynlist_search(Operation * op,SlapReply * rs)1666 dynlist_search( Operation *op, SlapReply *rs )
1667 {
1668 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1669 dynlist_gen_t *dlg = (dynlist_gen_t *)on->on_bi.bi_private;
1670 dynlist_info_t *dli;
1671 Operation o = *op;
1672 dynlist_map_t *dlm;
1673 Filter f[3];
1674 AttributeAssertion ava[2];
1675 AttributeName an[2] = {0};
1676
1677 slap_callback *sc;
1678 dynlist_search_t *ds;
1679 ObjectClass *static_oc;
1680 int nested, found, tmpwant;
1681 int opattrs, userattrs;
1682
1683 if ( get_manageDSAit( op ) )
1684 return SLAP_CB_CONTINUE;
1685
1686 sc = op->o_tmpcalloc( 1, sizeof(slap_callback)+sizeof(dynlist_search_t), op->o_tmpmemctx );
1687 sc->sc_private = (void *)(sc+1);
1688 ds = sc->sc_private;
1689
1690 memset( o.o_ctrlflag, 0, sizeof( o.o_ctrlflag ));
1691 o.o_managedsait = SLAP_CONTROL_CRITICAL;
1692
1693 /* Are we using memberOf, and does it affect this request? */
1694 if ( dlg->dlg_memberOf ) {
1695 int attrflags = slap_attr_flags( op->ors_attrs );
1696 opattrs = SLAP_OPATTRS( attrflags );
1697 userattrs = SLAP_USERATTRS( attrflags );
1698 }
1699
1700 /* Find all groups in scope. For group expansion
1701 * we only need the groups within the search scope, but
1702 * for memberOf populating, we need all dyngroups.
1703 */
1704 for ( dli = dlg->dlg_dli; dli; dli = dli->dli_next ) {
1705 static_oc = NULL;
1706 nested = 0;
1707 tmpwant = 0;
1708 if ( dlg->dlg_memberOf ) {
1709 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
1710 if ( dlm->dlm_memberOf_ad ) {
1711 int want = 0;
1712
1713 /* is attribute in filter? */
1714 if ( ad_infilter( dlm->dlm_memberOf_ad, op->ors_filter )) {
1715 want |= WANT_MEMBEROF;
1716 /* with nesting, filter attributes also require nestlink */
1717 if ( dlm->dlm_memberOf_nested ) {
1718 /* WANT_ flags have inverted meaning here:
1719 * to satisfy (memberOf=) filter, we need to also
1720 * find all subordinate groups. No special
1721 * treatment is needed for (member=) since we
1722 * already search all group entries.
1723 */
1724 want |= WANT_MEMBER;
1725 }
1726 }
1727
1728 /* if attribute is not requested, skip it */
1729 if ( op->ors_attrs == NULL ) {
1730 if ( !dlm->dlm_memberOf_oper ) {
1731 want |= WANT_MEMBEROF;
1732 if ( dlm->dlm_memberOf_nested && !dlm->dlm_member_oper )
1733 want |= WANT_MEMBER;
1734 }
1735 } else {
1736 if ( ad_inlist( dlm->dlm_memberOf_ad, op->ors_attrs )) {
1737 want |= WANT_MEMBEROF;
1738 if ( dlm->dlm_memberOf_nested && ad_inlist( dlm->dlm_member_ad, op->ors_attrs ))
1739 want |= WANT_MEMBER;
1740 } else {
1741 if ( opattrs ) {
1742 if ( dlm->dlm_memberOf_oper ) {
1743 want |= WANT_MEMBEROF;
1744 if ( dlm->dlm_memberOf_nested && dlm->dlm_member_oper )
1745 want |= WANT_MEMBER;
1746 }
1747 }
1748 if ( userattrs ) {
1749 if ( !dlm->dlm_memberOf_oper ) {
1750 want |= WANT_MEMBEROF;
1751 if ( dlm->dlm_memberOf_nested && !dlm->dlm_member_oper )
1752 want |= WANT_MEMBER;
1753 }
1754 }
1755 }
1756 }
1757 if ( want ) {
1758 nested = dlm->dlm_memberOf_nested;
1759 ds->ds_want = tmpwant = want;
1760 if ( dlm->dlm_static_oc ) {
1761 static_oc = dlm->dlm_static_oc;
1762 ds->ds_dlm = dlm;
1763 }
1764 }
1765 }
1766 }
1767 }
1768
1769 if ( static_oc ) {
1770 f[0].f_choice = LDAP_FILTER_OR;
1771 f[0].f_list = &f[1];
1772 f[0].f_next = NULL;
1773 f[1].f_choice = LDAP_FILTER_EQUALITY;
1774 f[1].f_next = &f[2];
1775 f[1].f_ava = &ava[0];
1776 f[1].f_av_desc = slap_schema.si_ad_objectClass;
1777 f[1].f_av_value = dli->dli_oc->soc_cname;
1778 f[2].f_choice = LDAP_FILTER_EQUALITY;
1779 f[2].f_ava = &ava[1];
1780 f[2].f_av_desc = slap_schema.si_ad_objectClass;
1781 f[2].f_av_value = static_oc->soc_cname;
1782 f[2].f_next = NULL;
1783 } else {
1784 f[0].f_choice = LDAP_FILTER_EQUALITY;
1785 f[0].f_ava = ava;
1786 f[0].f_av_desc = slap_schema.si_ad_objectClass;
1787 f[0].f_av_value = dli->dli_oc->soc_cname;
1788 f[0].f_next = NULL;
1789 }
1790
1791 if ( o.o_callback != sc ) {
1792 o.o_callback = sc;
1793 o.ors_filter = f;
1794 if ( tmpwant ) {
1795 o.o_req_dn = op->o_bd->be_suffix[0];
1796 o.o_req_ndn = op->o_bd->be_nsuffix[0];
1797 o.ors_scope = LDAP_SCOPE_SUBTREE;
1798 } else {
1799 o.o_req_dn = op->o_req_dn;
1800 o.o_req_ndn = op->o_req_ndn;
1801 o.ors_scope = op->ors_scope;
1802 }
1803 o.ors_attrsonly = 0;
1804 o.ors_attrs = an;
1805 o.o_bd = select_backend( op->o_bd->be_nsuffix, 1 );
1806 BER_BVZERO( &o.ors_filterstr );
1807 sc->sc_response = dynlist_search1resp;
1808 }
1809
1810 ds->ds_dli = dli;
1811 if ( o.ors_filterstr.bv_val )
1812 o.o_tmpfree( o.ors_filterstr.bv_val, o.o_tmpmemctx );
1813 filter2bv_x( &o, f, &o.ors_filterstr );
1814 an[0].an_desc = dli->dli_ad;
1815 an[0].an_name = dli->dli_ad->ad_cname;
1816 found = ds->ds_found;
1817 {
1818 SlapReply r = { REP_SEARCH };
1819 (void)o.o_bd->be_search( &o, &r );
1820 }
1821 if ( found != ds->ds_found && nested )
1822 dynlist_nestlink( op, ds );
1823 }
1824
1825 if ( ds->ds_names != NULL ) {
1826 sc->sc_response = dynlist_search2resp;
1827 sc->sc_cleanup = dynlist_search_cleanup;
1828 sc->sc_next = op->o_callback;
1829 op->o_callback = sc;
1830
1831 /* see if filter needs fixing */
1832 if ( dlg->dlg_memberOf ) {
1833 for ( dli = dlg->dlg_dli; dli; dli = dli->dli_next ) {
1834 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
1835 if ( dlm->dlm_memberOf_ad ) {
1836
1837 /* if attribute is in filter, fix it */
1838 if ( ad_infilter( dlm->dlm_memberOf_ad, op->ors_filter )) {
1839 ds->ds_dli = dli;
1840 ds->ds_dlm = dlm;
1841 dynlist_fix_filter( op, dlm->dlm_memberOf_ad, ds );
1842 }
1843 }
1844 }
1845 }
1846 }
1847
1848 } else {
1849 op->o_tmpfree( sc, op->o_tmpmemctx );
1850 }
1851 return SLAP_CB_CONTINUE;
1852 }
1853
1854 static int
dynlist_build_def_filter(dynlist_info_t * dli)1855 dynlist_build_def_filter( dynlist_info_t *dli )
1856 {
1857 char *ptr;
1858
1859 dli->dli_default_filter.bv_len = STRLENOF( "(!(objectClass=" "))" )
1860 + dli->dli_oc->soc_cname.bv_len;
1861 dli->dli_default_filter.bv_val = ch_malloc( dli->dli_default_filter.bv_len + 1 );
1862 if ( dli->dli_default_filter.bv_val == NULL ) {
1863 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: malloc failed.\n" );
1864 return -1;
1865 }
1866
1867 ptr = lutil_strcopy( dli->dli_default_filter.bv_val, "(!(objectClass=" );
1868 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
1869 ptr = lutil_strcopy( ptr, "))" );
1870
1871 assert( ptr == &dli->dli_default_filter.bv_val[dli->dli_default_filter.bv_len] );
1872
1873 return 0;
1874 }
1875
1876 enum {
1877 DL_ATTRSET = 1,
1878 DL_ATTRPAIR,
1879 DL_ATTRPAIR_COMPAT,
1880 DL_LAST
1881 };
1882
1883 static ConfigDriver dl_cfgen;
1884
1885 /* XXXmanu 255 is the maximum arguments we allow. Can we go beyond? */
1886 static ConfigTable dlcfg[] = {
1887 { "dynlist-attrset", "group-oc> [uri] <URL-ad> <[mapped:]member-ad> [...]",
1888 3, 0, 0, ARG_MAGIC|DL_ATTRSET, dl_cfgen,
1889 "( OLcfgOvAt:8.1 NAME ( 'olcDynListAttrSet' 'olcDlAttrSet' ) "
1890 "DESC 'Dynamic list: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1891 "EQUALITY caseIgnoreMatch "
1892 "SYNTAX OMsDirectoryString "
1893 "X-ORDERED 'VALUES' )",
1894 NULL, NULL },
1895 { "dynlist-attrpair", "member-ad> <URL-ad",
1896 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR, dl_cfgen,
1897 NULL, NULL, NULL },
1898 #ifdef TAKEOVER_DYNGROUP
1899 { "attrpair", "member-ad> <URL-ad",
1900 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR_COMPAT, dl_cfgen,
1901 NULL, NULL, NULL },
1902 #endif
1903 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1904 };
1905
1906 static ConfigOCs dlocs[] = {
1907 { "( OLcfgOvOc:8.1 "
1908 "NAME ( 'olcDynListConfig' 'olcDynamicList' ) "
1909 "DESC 'Dynamic list configuration' "
1910 "SUP olcOverlayConfig "
1911 "MAY olcDynListAttrSet )",
1912 Cft_Overlay, dlcfg, NULL, NULL },
1913 { NULL, 0, NULL }
1914 };
1915
1916 static int
dl_cfgen(ConfigArgs * c)1917 dl_cfgen( ConfigArgs *c )
1918 {
1919 slap_overinst *on = (slap_overinst *)c->bi;
1920 dynlist_gen_t *dlg = (dynlist_gen_t *)on->on_bi.bi_private;
1921 dynlist_info_t *dli = dlg->dlg_dli;
1922
1923 int rc = 0, i;
1924
1925 if ( c->op == SLAP_CONFIG_EMIT ) {
1926 switch( c->type ) {
1927 case DL_ATTRSET:
1928 for ( i = 0; dli; i++, dli = dli->dli_next ) {
1929 struct berval bv;
1930 char *ptr = c->cr_msg;
1931 dynlist_map_t *dlm;
1932
1933 assert( dli->dli_oc != NULL );
1934 assert( dli->dli_ad != NULL );
1935
1936 /* FIXME: check buffer overflow! */
1937 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1938 SLAP_X_ORDERED_FMT "%s", i,
1939 dli->dli_oc->soc_cname.bv_val );
1940
1941 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1942 *ptr++ = ' ';
1943 *ptr++ = '"';
1944 ptr = lutil_strncopy( ptr, dli->dli_uri.bv_val,
1945 dli->dli_uri.bv_len );
1946 *ptr++ = '"';
1947 }
1948
1949 *ptr++ = ' ';
1950 ptr = lutil_strncopy( ptr, dli->dli_ad->ad_cname.bv_val,
1951 dli->dli_ad->ad_cname.bv_len );
1952
1953 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
1954 ptr[ 0 ] = ' ';
1955 ptr++;
1956 if ( dlm->dlm_mapped_ad ) {
1957 ptr = lutil_strcopy( ptr, dlm->dlm_mapped_ad->ad_cname.bv_val );
1958 ptr[ 0 ] = ':';
1959 ptr++;
1960 }
1961
1962 ptr = lutil_strcopy( ptr, dlm->dlm_member_ad->ad_cname.bv_val );
1963
1964 if ( dlm->dlm_memberOf_ad ) {
1965 *ptr++ = '+';
1966 ptr = lutil_strcopy( ptr, dlm->dlm_memberOf_ad->ad_cname.bv_val );
1967 if ( dlm->dlm_static_oc ) {
1968 *ptr++ = '@';
1969 ptr = lutil_strcopy( ptr, dlm->dlm_static_oc->soc_cname.bv_val );
1970 }
1971 if ( dlm->dlm_memberOf_nested ) {
1972 *ptr++ = '*';
1973 }
1974 }
1975 }
1976
1977 bv.bv_val = c->cr_msg;
1978 bv.bv_len = ptr - bv.bv_val;
1979 value_add_one( &c->rvalue_vals, &bv );
1980 }
1981 break;
1982
1983 case DL_ATTRPAIR_COMPAT:
1984 case DL_ATTRPAIR:
1985 rc = 1;
1986 break;
1987
1988 default:
1989 rc = 1;
1990 break;
1991 }
1992
1993 return rc;
1994
1995 } else if ( c->op == LDAP_MOD_DELETE ) {
1996 switch( c->type ) {
1997 case DL_ATTRSET:
1998 if ( c->valx < 0 ) {
1999 dynlist_info_t *dli_next;
2000
2001 for ( dli_next = dli; dli_next; dli = dli_next ) {
2002 dynlist_map_t *dlm = dli->dli_dlm;
2003 dynlist_map_t *dlm_next;
2004
2005 dli_next = dli->dli_next;
2006
2007 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
2008 ch_free( dli->dli_uri.bv_val );
2009 }
2010
2011 if ( dli->dli_lud != NULL ) {
2012 ldap_free_urldesc( dli->dli_lud );
2013 }
2014
2015 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
2016 ber_memfree( dli->dli_uri_nbase.bv_val );
2017 }
2018
2019 if ( dli->dli_uri_filter != NULL ) {
2020 filter_free( dli->dli_uri_filter );
2021 }
2022
2023 ch_free( dli->dli_default_filter.bv_val );
2024
2025 while ( dlm != NULL ) {
2026 dlm_next = dlm->dlm_next;
2027 ch_free( dlm );
2028 dlm = dlm_next;
2029 }
2030 ch_free( dli );
2031 }
2032
2033 dlg->dlg_dli = NULL;
2034 dlg->dlg_memberOf = 0;
2035
2036 } else {
2037 dynlist_info_t **dlip;
2038 dynlist_map_t *dlm;
2039 dynlist_map_t *dlm_next;
2040
2041 for ( i = 0, dlip = (dynlist_info_t **)&dlg->dlg_dli;
2042 i < c->valx; i++ )
2043 {
2044 if ( *dlip == NULL ) {
2045 return 1;
2046 }
2047 dlip = &(*dlip)->dli_next;
2048 }
2049
2050 dli = *dlip;
2051 *dlip = dli->dli_next;
2052
2053 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
2054 ch_free( dli->dli_uri.bv_val );
2055 }
2056
2057 if ( dli->dli_lud != NULL ) {
2058 ldap_free_urldesc( dli->dli_lud );
2059 }
2060
2061 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
2062 ber_memfree( dli->dli_uri_nbase.bv_val );
2063 }
2064
2065 if ( dli->dli_uri_filter != NULL ) {
2066 filter_free( dli->dli_uri_filter );
2067 }
2068
2069 ch_free( dli->dli_default_filter.bv_val );
2070
2071 dlm = dli->dli_dlm;
2072 while ( dlm != NULL ) {
2073 dlm_next = dlm->dlm_next;
2074 if ( dlm->dlm_memberOf_ad )
2075 dlg->dlg_memberOf--;
2076 ch_free( dlm );
2077 dlm = dlm_next;
2078 }
2079 ch_free( dli );
2080
2081 dli = (dynlist_info_t *)dlg->dlg_dli;
2082 }
2083 break;
2084
2085 case DL_ATTRPAIR_COMPAT:
2086 case DL_ATTRPAIR:
2087 rc = 1;
2088 break;
2089
2090 default:
2091 rc = 1;
2092 break;
2093 }
2094
2095 return rc;
2096 }
2097
2098 switch( c->type ) {
2099 case DL_ATTRSET: {
2100 dynlist_info_t **dlip,
2101 *dli_next = NULL;
2102 ObjectClass *oc = NULL;
2103 AttributeDescription *ad = NULL;
2104 int attridx = 2;
2105 LDAPURLDesc *lud = NULL;
2106 struct berval nbase = BER_BVNULL;
2107 Filter *filter = NULL;
2108 struct berval uri = BER_BVNULL;
2109 dynlist_map_t *dlm = NULL, *dlml = NULL;
2110 const char *text;
2111
2112 oc = oc_find( c->argv[ 1 ] );
2113 if ( oc == NULL ) {
2114 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2115 "unable to find ObjectClass \"%s\"",
2116 c->argv[ 1 ] );
2117 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2118 c->log, c->cr_msg );
2119 return 1;
2120 }
2121
2122 if ( strncasecmp( c->argv[ attridx ], "ldap://", STRLENOF("ldap://") ) == 0 ) {
2123 if ( ldap_url_parse( c->argv[ attridx ], &lud ) != LDAP_URL_SUCCESS ) {
2124 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2125 "unable to parse URI \"%s\"",
2126 c->argv[ attridx ] );
2127 rc = 1;
2128 goto done_uri;
2129 }
2130
2131 if ( lud->lud_host != NULL ) {
2132 if ( lud->lud_host[0] == '\0' ) {
2133 ch_free( lud->lud_host );
2134 lud->lud_host = NULL;
2135
2136 } else {
2137 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2138 "host not allowed in URI \"%s\"",
2139 c->argv[ attridx ] );
2140 rc = 1;
2141 goto done_uri;
2142 }
2143 }
2144
2145 if ( lud->lud_attrs != NULL ) {
2146 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2147 "attrs not allowed in URI \"%s\"",
2148 c->argv[ attridx ] );
2149 rc = 1;
2150 goto done_uri;
2151 }
2152
2153 if ( lud->lud_exts != NULL ) {
2154 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2155 "extensions not allowed in URI \"%s\"",
2156 c->argv[ attridx ] );
2157 rc = 1;
2158 goto done_uri;
2159 }
2160
2161 if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' ) {
2162 struct berval dn;
2163 ber_str2bv( lud->lud_dn, 0, 0, &dn );
2164 rc = dnNormalize( 0, NULL, NULL, &dn, &nbase, NULL );
2165 if ( rc != LDAP_SUCCESS ) {
2166 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2167 "DN normalization failed in URI \"%s\"",
2168 c->argv[ attridx ] );
2169 goto done_uri;
2170 }
2171 }
2172
2173 if ( lud->lud_filter != NULL && lud->lud_filter[ 0 ] != '\0' ) {
2174 filter = str2filter( lud->lud_filter );
2175 if ( filter == NULL ) {
2176 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2177 "filter parsing failed in URI \"%s\"",
2178 c->argv[ attridx ] );
2179 rc = 1;
2180 goto done_uri;
2181 }
2182 }
2183
2184 ber_str2bv( c->argv[ attridx ], 0, 1, &uri );
2185
2186 done_uri:;
2187 if ( rc ) {
2188 if ( lud ) {
2189 ldap_free_urldesc( lud );
2190 }
2191
2192 if ( !BER_BVISNULL( &nbase ) ) {
2193 ber_memfree( nbase.bv_val );
2194 }
2195
2196 if ( filter != NULL ) {
2197 filter_free( filter );
2198 }
2199
2200 while ( dlm != NULL ) {
2201 dlml = dlm;
2202 dlm = dlm->dlm_next;
2203 ch_free( dlml );
2204 }
2205
2206 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2207 c->log, c->cr_msg );
2208
2209 return rc;
2210 }
2211
2212 attridx++;
2213 }
2214
2215 rc = slap_str2ad( c->argv[ attridx ], &ad, &text );
2216 if ( rc != LDAP_SUCCESS ) {
2217 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2218 "unable to find AttributeDescription \"%s\"",
2219 c->argv[ attridx ] );
2220 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2221 c->log, c->cr_msg );
2222 rc = 1;
2223 goto done_uri;
2224 }
2225
2226 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
2227 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
2228 "AttributeDescription \"%s\" "
2229 "must be a subtype of \"labeledURI\"",
2230 c->argv[ attridx ] );
2231 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2232 c->log, c->cr_msg );
2233 rc = 1;
2234 goto done_uri;
2235 }
2236
2237 attridx++;
2238
2239 for ( i = attridx; i < c->argc; i++ ) {
2240 char *arg;
2241 char *cp;
2242 AttributeDescription *member_ad = NULL;
2243 AttributeDescription *mapped_ad = NULL;
2244 AttributeDescription *memberOf_ad = NULL;
2245 ObjectClass *static_oc = NULL;
2246 int nested = 0;
2247 dynlist_map_t *dlmp;
2248
2249
2250 /*
2251 * If no mapped attribute is given, dn is used
2252 * for backward compatibility.
2253 */
2254 arg = c->argv[i];
2255 if ( ( cp = strchr( arg, ':' ) ) != NULL ) {
2256 struct berval bv;
2257 ber_str2bv( arg, cp - arg, 0, &bv );
2258 rc = slap_bv2ad( &bv, &mapped_ad, &text );
2259 if ( rc != LDAP_SUCCESS ) {
2260 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2261 DYNLIST_USAGE
2262 "unable to find mapped AttributeDescription #%d \"%s\"\n",
2263 i - 3, c->argv[ i ] );
2264 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2265 c->log, c->cr_msg );
2266 rc = 1;
2267 goto done_uri;
2268 }
2269 arg = cp + 1;
2270 }
2271 if ( ( cp = strchr( arg, '+' ) ) != NULL ) {
2272 struct berval bv;
2273 char *ocp, *np;
2274 np = strrchr( cp+1, '*' );
2275 if ( np ) {
2276 nested = 1;
2277 *np = '\0';
2278 }
2279 ocp = strchr( cp+1, '@' );
2280 if ( ocp ) {
2281 static_oc = oc_find( ocp+1 );
2282 if ( !static_oc ) {
2283 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2284 DYNLIST_USAGE
2285 "unable to find static-oc ObjectClass #%d \"%s\"\n",
2286 i - 3, c->argv[ i ] );
2287 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2288 c->log, c->cr_msg );
2289 rc = 1;
2290 goto done_uri;
2291 }
2292 *ocp = '\0';
2293 }
2294 ber_str2bv( cp+1, 0, 0, &bv );
2295 rc = slap_bv2ad( &bv, &memberOf_ad, &text );
2296 if ( rc != LDAP_SUCCESS ) {
2297 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2298 DYNLIST_USAGE
2299 "unable to find memberOf AttributeDescription #%d \"%s\"\n",
2300 i - 3, c->argv[ i ] );
2301 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2302 c->log, c->cr_msg );
2303 rc = 1;
2304 goto done_uri;
2305 }
2306 dlg->dlg_memberOf++;
2307 *cp = '\0';
2308 }
2309
2310 rc = slap_str2ad( arg, &member_ad, &text );
2311 if ( rc != LDAP_SUCCESS ) {
2312 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2313 DYNLIST_USAGE
2314 "unable to find AttributeDescription #%d \"%s\"\n",
2315 i - 3, c->argv[ i ] );
2316 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2317 c->log, c->cr_msg );
2318 rc = 1;
2319 goto done_uri;
2320 }
2321
2322 dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
2323 if ( dlm == NULL ) {
2324 dlm = dlmp;
2325 }
2326 dlmp->dlm_member_ad = member_ad;
2327 dlmp->dlm_mapped_ad = mapped_ad;
2328 dlmp->dlm_memberOf_ad = memberOf_ad;
2329 dlmp->dlm_static_oc = static_oc;
2330 dlmp->dlm_memberOf_nested = nested;
2331 dlmp->dlm_member_oper = is_at_operational( member_ad->ad_type );
2332 if ( memberOf_ad ) {
2333 dlmp->dlm_memberOf_oper = is_at_operational( memberOf_ad->ad_type );
2334 } else {
2335 dlmp->dlm_memberOf_oper = 0;
2336 }
2337 dlmp->dlm_next = NULL;
2338
2339 if ( dlml != NULL )
2340 dlml->dlm_next = dlmp;
2341 dlml = dlmp;
2342 }
2343
2344 if ( c->valx > 0 ) {
2345 int i;
2346
2347 for ( i = 0, dlip = (dynlist_info_t **)&dlg->dlg_dli;
2348 i < c->valx; i++ )
2349 {
2350 if ( *dlip == NULL ) {
2351 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2352 DYNLIST_USAGE
2353 "invalid index {%d}\n",
2354 c->valx );
2355 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2356 c->log, c->cr_msg );
2357 rc = 1;
2358 goto done_uri;
2359 }
2360 dlip = &(*dlip)->dli_next;
2361 }
2362 dli_next = *dlip;
2363
2364 } else {
2365 for ( dlip = (dynlist_info_t **)&dlg->dlg_dli;
2366 *dlip; dlip = &(*dlip)->dli_next )
2367 /* goto last */;
2368 }
2369
2370 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
2371
2372 (*dlip)->dli_oc = oc;
2373 (*dlip)->dli_ad = ad;
2374 (*dlip)->dli_dlm = dlm;
2375 (*dlip)->dli_next = dli_next;
2376
2377 (*dlip)->dli_lud = lud;
2378 (*dlip)->dli_uri_nbase = nbase;
2379 (*dlip)->dli_uri_filter = filter;
2380 (*dlip)->dli_uri = uri;
2381
2382 rc = dynlist_build_def_filter( *dlip );
2383
2384 } break;
2385
2386 case DL_ATTRPAIR_COMPAT:
2387 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2388 "warning: \"attrpair\" only supported for limited "
2389 "backward compatibility with overlay \"dyngroup\"" );
2390 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2391 /* fallthru */
2392
2393 case DL_ATTRPAIR: {
2394 dynlist_info_t **dlip;
2395 ObjectClass *oc = NULL;
2396 AttributeDescription *ad = NULL,
2397 *member_ad = NULL;
2398 const char *text;
2399
2400 oc = oc_find( "groupOfURLs" );
2401 if ( oc == NULL ) {
2402 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2403 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
2404 "unable to find default ObjectClass \"groupOfURLs\"" );
2405 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2406 c->log, c->cr_msg );
2407 return 1;
2408 }
2409
2410 rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text );
2411 if ( rc != LDAP_SUCCESS ) {
2412 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2413 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
2414 "unable to find AttributeDescription \"%s\"",
2415 c->argv[ 1 ] );
2416 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2417 c->log, c->cr_msg );
2418 return 1;
2419 }
2420
2421 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
2422 if ( rc != LDAP_SUCCESS ) {
2423 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2424 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
2425 "unable to find AttributeDescription \"%s\"\n",
2426 c->argv[ 2 ] );
2427 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2428 c->log, c->cr_msg );
2429 return 1;
2430 }
2431
2432 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
2433 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2434 DYNLIST_USAGE
2435 "AttributeDescription \"%s\" "
2436 "must be a subtype of \"labeledURI\"",
2437 c->argv[ 2 ] );
2438 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2439 c->log, c->cr_msg );
2440 return 1;
2441 }
2442
2443 for ( dlip = (dynlist_info_t **)&dlg->dlg_dli;
2444 *dlip; dlip = &(*dlip)->dli_next )
2445 {
2446 /*
2447 * The same URL attribute / member attribute pair
2448 * cannot be repeated, but we enforce this only
2449 * when the member attribute is unique. Performing
2450 * the check for multiple values would require
2451 * sorting and comparing the lists, which is left
2452 * as a future improvement
2453 */
2454 if ( (*dlip)->dli_ad == ad &&
2455 (*dlip)->dli_dlm->dlm_next == NULL &&
2456 member_ad == (*dlip)->dli_dlm->dlm_member_ad ) {
2457 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2458 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
2459 "URL attributeDescription \"%s\" already mapped.\n",
2460 ad->ad_cname.bv_val );
2461 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2462 c->log, c->cr_msg );
2463 #if 0
2464 /* make it a warning... */
2465 return 1;
2466 #endif
2467 }
2468 }
2469
2470 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
2471
2472 (*dlip)->dli_oc = oc;
2473 (*dlip)->dli_ad = ad;
2474 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
2475 (*dlip)->dli_dlm->dlm_member_ad = member_ad;
2476 (*dlip)->dli_dlm->dlm_mapped_ad = NULL;
2477
2478 rc = dynlist_build_def_filter( *dlip );
2479
2480 } break;
2481
2482 default:
2483 rc = 1;
2484 break;
2485 }
2486
2487 return rc;
2488 }
2489
2490 static int
dynlist_db_init(BackendDB * be,ConfigReply * cr)2491 dynlist_db_init(
2492 BackendDB *be,
2493 ConfigReply *cr)
2494 {
2495 slap_overinst *on = (slap_overinst *)be->bd_info;
2496 dynlist_gen_t *dlg;
2497
2498 dlg = (dynlist_gen_t *)ch_malloc( sizeof( *dlg ));
2499 on->on_bi.bi_private = dlg;
2500 dlg->dlg_dli = NULL;
2501 dlg->dlg_memberOf = 0;
2502
2503 return 0;
2504 }
2505
2506 static int
dynlist_db_open(BackendDB * be,ConfigReply * cr)2507 dynlist_db_open(
2508 BackendDB *be,
2509 ConfigReply *cr )
2510 {
2511 slap_overinst *on = (slap_overinst *) be->bd_info;
2512 dynlist_gen_t *dlg = (dynlist_gen_t *)on->on_bi.bi_private;
2513 dynlist_info_t *dli = dlg->dlg_dli;
2514 ObjectClass *oc = NULL;
2515 AttributeDescription *ad = NULL;
2516 const char *text;
2517 int rc;
2518
2519 if ( dli == NULL ) {
2520 dli = ch_calloc( 1, sizeof( dynlist_info_t ) );
2521 dlg->dlg_dli = dli;
2522 }
2523
2524 for ( ; dli; dli = dli->dli_next ) {
2525 if ( dli->dli_oc == NULL ) {
2526 if ( oc == NULL ) {
2527 oc = oc_find( "groupOfURLs" );
2528 if ( oc == NULL ) {
2529 snprintf( cr->msg, sizeof( cr->msg),
2530 "unable to fetch objectClass \"groupOfURLs\"" );
2531 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg );
2532 return 1;
2533 }
2534 }
2535
2536 dli->dli_oc = oc;
2537 }
2538
2539 if ( dli->dli_ad == NULL ) {
2540 if ( ad == NULL ) {
2541 rc = slap_str2ad( "memberURL", &ad, &text );
2542 if ( rc != LDAP_SUCCESS ) {
2543 snprintf( cr->msg, sizeof( cr->msg),
2544 "unable to fetch attributeDescription \"memberURL\": %d (%s)",
2545 rc, text );
2546 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg );
2547 return 1;
2548 }
2549 }
2550
2551 dli->dli_ad = ad;
2552 }
2553
2554 if ( BER_BVISNULL( &dli->dli_default_filter ) ) {
2555 rc = dynlist_build_def_filter( dli );
2556 if ( rc != 0 ) {
2557 return rc;
2558 }
2559 }
2560 }
2561
2562 if ( ad_dgIdentity == NULL ) {
2563 rc = slap_str2ad( "dgIdentity", &ad_dgIdentity, &text );
2564 if ( rc != LDAP_SUCCESS ) {
2565 snprintf( cr->msg, sizeof( cr->msg),
2566 "unable to fetch attributeDescription \"dgIdentity\": %d (%s)",
2567 rc, text );
2568 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg );
2569 /* Just a warning */
2570 }
2571 }
2572
2573 if ( ad_dgAuthz == NULL ) {
2574 rc = slap_str2ad( "dgAuthz", &ad_dgAuthz, &text );
2575 if ( rc != LDAP_SUCCESS ) {
2576 snprintf( cr->msg, sizeof( cr->msg),
2577 "unable to fetch attributeDescription \"dgAuthz\": %d (%s)",
2578 rc, text );
2579 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg );
2580 /* Just a warning */
2581 }
2582 }
2583
2584 return 0;
2585 }
2586
2587 static int
dynlist_db_destroy(BackendDB * be,ConfigReply * cr)2588 dynlist_db_destroy(
2589 BackendDB *be,
2590 ConfigReply *cr )
2591 {
2592 slap_overinst *on = (slap_overinst *) be->bd_info;
2593
2594 if ( on->on_bi.bi_private ) {
2595 dynlist_gen_t *dlg = (dynlist_gen_t *)on->on_bi.bi_private;
2596 dynlist_info_t *dli = dlg->dlg_dli,
2597 *dli_next;
2598
2599 for ( dli_next = dli; dli_next; dli = dli_next ) {
2600 dynlist_map_t *dlm;
2601 dynlist_map_t *dlm_next;
2602
2603 dli_next = dli->dli_next;
2604
2605 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
2606 ch_free( dli->dli_uri.bv_val );
2607 }
2608
2609 if ( dli->dli_lud != NULL ) {
2610 ldap_free_urldesc( dli->dli_lud );
2611 }
2612
2613 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
2614 ber_memfree( dli->dli_uri_nbase.bv_val );
2615 }
2616
2617 if ( dli->dli_uri_filter != NULL ) {
2618 filter_free( dli->dli_uri_filter );
2619 }
2620
2621 ch_free( dli->dli_default_filter.bv_val );
2622
2623 dlm = dli->dli_dlm;
2624 while ( dlm != NULL ) {
2625 dlm_next = dlm->dlm_next;
2626 ch_free( dlm );
2627 dlm = dlm_next;
2628 }
2629 ch_free( dli );
2630 }
2631 ch_free( dlg );
2632 }
2633
2634 return 0;
2635 }
2636
2637 static slap_overinst dynlist = { { NULL } };
2638 #ifdef TAKEOVER_DYNGROUP
2639 static char *obsolete_names[] = {
2640 "dyngroup",
2641 NULL
2642 };
2643 #endif
2644
2645 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
2646 static
2647 #endif /* SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC */
2648 int
dynlist_initialize(void)2649 dynlist_initialize(void)
2650 {
2651 const char *text;
2652 int rc = 0;
2653
2654 /* See if we need to define memberOf opattr */
2655 rc = slap_str2ad( "memberOf", &ad_memberOf, &text );
2656 if ( rc ) {
2657 rc = register_at(
2658 "( 1.2.840.113556.1.2.102 "
2659 "NAME 'memberOf' "
2660 "DESC 'Group that the entry belongs to' "
2661 "SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' "
2662 "EQUALITY distinguishedNameMatch " /* added */
2663 "USAGE dSAOperation " /* added; questioned */
2664 "NO-USER-MODIFICATION " /* added */
2665 "X-ORIGIN 'iPlanet Delegated Administrator' )",
2666 &ad_memberOf, 0 );
2667 if ( rc ) {
2668 Debug( LDAP_DEBUG_ANY,
2669 "dynlist_initialize: register_at (memberOf) failed\n" );
2670 return rc;
2671 }
2672 }
2673
2674 dynlist.on_bi.bi_type = "dynlist";
2675
2676 #ifdef TAKEOVER_DYNGROUP
2677 /* makes dynlist incompatible with dyngroup */
2678 dynlist.on_bi.bi_obsolete_names = obsolete_names;
2679 #endif
2680
2681 dynlist.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
2682 dynlist.on_bi.bi_db_init = dynlist_db_init;
2683 dynlist.on_bi.bi_db_config = config_generic_wrapper;
2684 dynlist.on_bi.bi_db_open = dynlist_db_open;
2685 dynlist.on_bi.bi_db_destroy = dynlist_db_destroy;
2686
2687 dynlist.on_bi.bi_op_search = dynlist_search;
2688 dynlist.on_bi.bi_op_compare = dynlist_compare;
2689
2690 dynlist.on_bi.bi_cf_ocs = dlocs;
2691
2692 rc = config_register_schema( dlcfg, dlocs );
2693 if ( rc ) {
2694 return rc;
2695 }
2696
2697 return overlay_register( &dynlist );
2698 }
2699
2700 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
2701 int
init_module(int argc,char * argv[])2702 init_module( int argc, char *argv[] )
2703 {
2704 return dynlist_initialize();
2705 }
2706 #endif
2707
2708 #endif /* SLAPD_OVER_DYNLIST */
2709