]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/dynlist.c
85d45205284a2d6574e4ebe02293a46644d5f20a
[openldap] / servers / slapd / overlays / dynlist.c
1 /* dynlist.c - dynamic list overlay */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2007 The OpenLDAP Foundation.
6  * Portions Copyright 2004-2005 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati
19  * for SysNet s.n.c., for inclusion in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #ifdef SLAPD_OVER_DYNLIST
25
26 #if LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR > 3
27 #if SLAPD_OVER_DYNGROUP != SLAPD_MOD_STATIC
28 #define TAKEOVER_DYNGROUP
29 #endif
30 #else
31 #if LDAP_VENDOR_VERSION_MINOR < 3
32 #define OL_2_2_COMPAT
33 #endif
34 #endif
35
36 #include <stdio.h>
37
38 #include <ac/string.h>
39
40 #include "slap.h"
41 #ifndef OL_2_2_COMPAT
42 #include "config.h"
43 #endif
44 #include "lutil.h"
45
46 /* FIXME: the code differs if SLAP_OPATTRS is defined or not;
47  * SLAP_OPATTRS is not defined in 2.2 yet, while this overlay
48  * expects HEAD code at least later than August 6, 2004. */
49 /* FIXME: slap_anlist_no_attrs was introduced in 2.3; here it
50  * is anticipated to allow using this overlay with 2.2. */
51
52 #ifdef OL_2_2_COMPAT
53 static AttributeName anlist_no_attrs[] = {
54         { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL },
55         { BER_BVNULL, NULL, 0, NULL }
56 };
57
58 static AttributeName *slap_anlist_no_attrs = anlist_no_attrs;
59 #endif
60
61 static AttributeDescription *ad_dgIdentity;
62
63 typedef struct dynlist_info_t {
64         ObjectClass             *dli_oc;
65         AttributeDescription    *dli_ad;
66         AttributeDescription    *dli_member_ad;
67         struct berval           dli_default_filter;
68         struct dynlist_info_t   *dli_next;
69 } dynlist_info_t;
70
71 static dynlist_info_t *
72 dynlist_is_dynlist_next( Operation *op, SlapReply *rs, dynlist_info_t *old_dli )
73 {
74         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
75         dynlist_info_t  *dli;
76
77         Attribute       *a;
78
79         if ( old_dli == NULL ) {
80                 dli = (dynlist_info_t *)on->on_bi.bi_private;
81
82         } else {
83                 dli = old_dli->dli_next;
84         }
85
86         a = attrs_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
87         if ( a == NULL ) {
88                 /* FIXME: objectClass must be present; for non-storage
89                  * backends, like back-ldap, it needs to be added
90                  * to the requested attributes */
91                 return NULL;
92         }
93
94         for ( ; dli; dli = dli->dli_next ) {
95                 if ( value_find_ex( slap_schema.si_ad_objectClass, 
96                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
97                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
98                                 a->a_nvals, &dli->dli_oc->soc_cname,
99                                 op->o_tmpmemctx ) == 0 )
100                 {
101                         return dli;
102                 }
103         }
104
105         return NULL;
106 }
107
108 static int
109 dynlist_make_filter( Operation *op, struct berval *oldf, struct berval *newf )
110 {
111         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
112         dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private;
113
114         char            *ptr;
115
116         assert( oldf != NULL );
117         assert( newf != NULL );
118         assert( !BER_BVISNULL( oldf ) );
119         assert( !BER_BVISEMPTY( oldf ) );
120
121         newf->bv_len = STRLENOF( "(&(!(objectClass=" "))" ")" )
122                 + dli->dli_oc->soc_cname.bv_len + oldf->bv_len;
123         newf->bv_val = op->o_tmpalloc( newf->bv_len + 1, op->o_tmpmemctx );
124         if ( newf->bv_val == NULL ) {
125                 return -1;
126         }
127         ptr = lutil_strcopy( newf->bv_val, "(&(!(objectClass=" );
128         ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
129         ptr = lutil_strcopy( ptr, "))" );
130         ptr = lutil_strcopy( ptr, oldf->bv_val );
131         ptr = lutil_strcopy( ptr, ")" );
132         newf->bv_len = ptr - newf->bv_val;
133
134         return 0;
135 }
136
137 typedef struct dynlist_sc_t {
138         dynlist_info_t    *dlc_dli;
139         Entry           *dlc_e;
140 } dynlist_sc_t;
141
142 static int
143 dynlist_sc_update( Operation *op, SlapReply *rs )
144 {
145         Entry                   *e;
146         Attribute               *a;
147         int                     opattrs,
148                                 userattrs;
149         AccessControlState      acl_state = ACL_STATE_INIT;
150
151         dynlist_sc_t            *dlc;
152
153         if ( rs->sr_type != REP_SEARCH ) {
154                 return 0;
155         }
156
157         dlc = (dynlist_sc_t *)op->o_callback->sc_private;
158         e = dlc->dlc_e;
159
160         assert( e != NULL );
161         assert( rs->sr_entry != NULL );
162
163         /* test access to entry */
164         if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
165                                 NULL, ACL_READ, NULL ) )
166         {
167                 goto done;
168         }
169
170         if ( dlc->dlc_dli->dli_member_ad ) {
171
172                 /* if access allowed, try to add values, emulating permissive
173                  * control to silently ignore duplicates */
174                 if ( access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
175                                         NULL, ACL_READ, NULL ) )
176                 {
177                         Modification    mod;
178                         const char      *text = NULL;
179                         char            textbuf[1024];
180                         struct berval   vals[ 2 ], nvals[ 2 ];
181
182                         vals[ 0 ] = rs->sr_entry->e_name;
183                         BER_BVZERO( &vals[ 1 ] );
184                         nvals[ 0 ] = rs->sr_entry->e_nname;
185                         BER_BVZERO( &nvals[ 1 ] );
186
187                         mod.sm_op = LDAP_MOD_ADD;
188                         mod.sm_desc = dlc->dlc_dli->dli_member_ad;
189                         mod.sm_type = dlc->dlc_dli->dli_member_ad->ad_cname;
190                         mod.sm_values = vals;
191                         mod.sm_nvalues = nvals;
192
193                         (void)modify_add_values( e, &mod, /* permissive */ 1,
194                                         &text, textbuf, sizeof( textbuf ) );
195                 }
196
197                 goto done;
198         }
199
200 #ifndef SLAP_OPATTRS
201         opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
202         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
203 #else /* SLAP_OPATTRS */
204         opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
205         userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
206 #endif /* SLAP_OPATTRS */
207
208         for ( a = rs->sr_entry->e_attrs; a != NULL; a = a->a_next ) {
209                 BerVarray       vals, nvals = NULL;
210                 int             i, j,
211                                 is_oc = a->a_desc == slap_schema.si_ad_objectClass;
212
213                 /* if attribute is not requested, skip it */
214                 if ( rs->sr_attrs == NULL ) {
215                         if ( is_at_operational( a->a_desc->ad_type ) ) {
216                                 continue;
217                         }
218
219                 } else {
220                         if ( is_at_operational( a->a_desc->ad_type ) ) {
221                                 if ( !opattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
222                                 {
223                                         continue;
224                                 }
225
226                         } else {
227                                 if ( !userattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
228                                 {
229                                         continue;
230                                 }
231                         }
232                 }
233
234                 /* test access to attribute */
235                 if ( op->ors_attrsonly ) {
236                         if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL,
237                                                 ACL_READ, &acl_state ) )
238                         {
239                                 continue;
240                         }
241                 }
242
243                 /* single-value check: keep first only */
244                 if ( is_at_single_value( a->a_desc->ad_type ) ) {
245                         if ( attr_find( e->e_attrs, a->a_desc ) != NULL ) {
246                                 continue;
247                         }
248                 }
249
250                 /* test access to attribute */
251                 for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ )
252                         /* just count */ ;
253
254                 vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
255                 if ( a->a_nvals != a->a_vals ) {
256                         nvals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
257                 }
258
259                 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
260                         if ( is_oc ) {
261                                 ObjectClass     *soc = oc_bvfind( &a->a_vals[i] );
262
263                                 if ( soc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) {
264                                         continue;
265                                 }
266                         }
267
268                         if ( access_allowed( op, rs->sr_entry, a->a_desc,
269                                                 &a->a_nvals[i], ACL_READ, &acl_state ) )
270                         {
271                                 vals[j] = a->a_vals[i];
272                                 if ( nvals ) {
273                                         nvals[j] = a->a_nvals[i];
274                                 }
275                                 j++;
276                         }
277                 }
278
279                 /* if access allowed, try to add values, emulating permissive
280                  * control to silently ignore duplicates */
281                 if ( j != 0 ) {
282                         Modification    mod;
283                         const char      *text = NULL;
284                         char            textbuf[1024];
285
286                         BER_BVZERO( &vals[j] );
287                         if ( nvals ) {
288                                 BER_BVZERO( &nvals[j] );
289                         }
290
291                         mod.sm_op = LDAP_MOD_ADD;
292                         mod.sm_desc = a->a_desc;
293                         mod.sm_type = a->a_desc->ad_cname;
294                         mod.sm_values = vals;
295                         mod.sm_nvalues = nvals;
296
297                         (void)modify_add_values( e, &mod, /* permissive */ 1,
298                                         &text, textbuf, sizeof( textbuf ) );
299                 }
300
301                 op->o_tmpfree( vals, op->o_tmpmemctx );
302                 if ( nvals ) {
303                         op->o_tmpfree( nvals, op->o_tmpmemctx );
304                 }
305         }
306
307 done:;
308         if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
309                 entry_free( rs->sr_entry );
310                 rs->sr_entry = NULL;
311                 rs->sr_flags ^= REP_ENTRY_MUSTBEFREED;
312         }
313
314         return 0;
315 }
316         
317 static int
318 dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli )
319 {
320         Attribute       *a, *id = NULL;
321         slap_callback   cb;
322         Operation       o = *op;
323         SlapReply       r = { REP_SEARCH };
324         struct berval   *url;
325         Entry           *e;
326         slap_mask_t     e_flags;
327         int             opattrs,
328                         userattrs;
329         dynlist_sc_t    dlc = { 0 };
330
331         a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad );
332         if ( a == NULL ) {
333                 /* FIXME: error? */
334                 return SLAP_CB_CONTINUE;
335         }
336
337 #ifndef SLAP_OPATTRS
338         opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
339         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
340 #else /* SLAP_OPATTRS */
341         opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
342         userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
343 #endif /* SLAP_OPATTRS */
344
345         /* Don't generate member list if it wasn't requested */
346         if ( dli->dli_member_ad && !userattrs && !ad_inlist( dli->dli_member_ad, rs->sr_attrs ) ) {
347                 return SLAP_CB_CONTINUE;
348         }
349
350         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
351                 e = entry_dup( rs->sr_entry );
352         } else {
353                 e = rs->sr_entry;
354         }
355         e_flags = rs->sr_flags | ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
356
357         if ( ad_dgIdentity && ( id = attrs_find( e->e_attrs, ad_dgIdentity ))) {
358                 o.o_dn = id->a_vals[0];
359                 o.o_ndn = id->a_nvals[0];
360                 o.o_groups = NULL;
361         }
362
363         dlc.dlc_e = e;
364         dlc.dlc_dli = dli;
365         cb.sc_private = &dlc;
366         cb.sc_response = dynlist_sc_update;
367         cb.sc_cleanup = NULL;
368         cb.sc_next = NULL;
369
370         o.o_callback = &cb;
371         o.ors_deref = LDAP_DEREF_NEVER;
372         o.ors_limit = NULL;
373         o.ors_tlimit = SLAP_NO_LIMIT;
374         o.ors_slimit = SLAP_NO_LIMIT;
375
376         for ( url = a->a_nvals; !BER_BVISNULL( url ); url++ ) {
377                 LDAPURLDesc     *lud = NULL;
378                 int             i, j;
379                 struct berval   dn;
380                 int             rc;
381
382                 BER_BVZERO( &o.o_req_dn );
383                 BER_BVZERO( &o.o_req_ndn );
384                 o.ors_filter = NULL;
385                 o.ors_attrs = NULL;
386                 BER_BVZERO( &o.ors_filterstr );
387
388                 if ( ldap_url_parse( url->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
389                         /* FIXME: error? */
390                         continue;
391                 }
392
393                 if ( lud->lud_host != NULL ) {
394                         /* FIXME: host not allowed; reject as illegal? */
395                         Debug( LDAP_DEBUG_ANY, "dynlist_prepare_entry(\"%s\"): "
396                                 "illegal URI \"%s\"\n",
397                                 e->e_name.bv_val, url->bv_val, 0 );
398                         goto cleanup;
399                 }
400
401                 if ( lud->lud_dn == NULL ) {
402                         /* note that an empty base is not honored in terms
403                          * of defaultSearchBase, because select_backend()
404                          * is not aware of the defaultSearchBase option;
405                          * this can be useful in case of a database serving
406                          * the empty suffix */
407                         BER_BVSTR( &dn, "" );
408
409                 } else {
410                         ber_str2bv( lud->lud_dn, 0, 0, &dn );
411                 }
412                 rc = dnPrettyNormal( NULL, &dn, &o.o_req_dn, &o.o_req_ndn, op->o_tmpmemctx );
413                 if ( rc != LDAP_SUCCESS ) {
414                         /* FIXME: error? */
415                         goto cleanup;
416                 }
417                 o.ors_scope = lud->lud_scope;
418
419                 if ( dli->dli_member_ad != NULL ) {
420                         /* if ( lud->lud_attrs != NULL ),
421                          * the URL should be ignored */
422                         o.ors_attrs = slap_anlist_no_attrs;
423
424                 } else if ( lud->lud_attrs == NULL ) {
425                         o.ors_attrs = rs->sr_attrs;
426
427                 } else {
428                         for ( i = 0; lud->lud_attrs[i]; i++)
429                                 /* just count */ ;
430
431                         o.ors_attrs = op->o_tmpcalloc( i + 1, sizeof( AttributeName ), op->o_tmpmemctx );
432                         for ( i = 0, j = 0; lud->lud_attrs[i]; i++) {
433                                 const char      *text = NULL;
434         
435                                 ber_str2bv( lud->lud_attrs[i], 0, 0, &o.ors_attrs[j].an_name );
436                                 o.ors_attrs[j].an_desc = NULL;
437                                 (void)slap_bv2ad( &o.ors_attrs[j].an_name, &o.ors_attrs[j].an_desc, &text );
438                                 /* FIXME: ignore errors... */
439
440                                 if ( rs->sr_attrs == NULL ) {
441                                         if ( o.ors_attrs[j].an_desc != NULL &&
442                                                         is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
443                                         {
444                                                 continue;
445                                         }
446
447                                 } else {
448                                         if ( o.ors_attrs[j].an_desc != NULL &&
449                                                         is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
450                                         {
451                                                 if ( !opattrs && !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
452                                                 {
453                                                         continue;
454                                                 }
455
456                                         } else {
457                                                 if ( !userattrs && 
458                                                                 o.ors_attrs[j].an_desc != NULL &&
459                                                                 !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
460                                                 {
461                                                         continue;
462                                                 }
463                                         }
464                                 }
465
466                                 j++;
467                         }
468
469                         if ( j == 0 ) {
470                                 goto cleanup;
471                         }
472                 
473                         BER_BVZERO( &o.ors_attrs[j].an_name );
474                 }
475
476                 if ( lud->lud_filter == NULL ) {
477                         ber_dupbv_x( &o.ors_filterstr,
478                                         &dli->dli_default_filter, op->o_tmpmemctx );
479
480                 } else {
481                         struct berval   flt;
482                         ber_str2bv( lud->lud_filter, 0, 0, &flt );
483                         if ( dynlist_make_filter( op, &flt, &o.ors_filterstr ) ) {
484                                 /* error */
485                                 goto cleanup;
486                         }
487                 }
488                 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
489                 if ( o.ors_filter == NULL ) {
490                         goto cleanup;
491                 }
492                 
493                 o.o_bd = select_backend( &o.o_req_ndn, 1 );
494                 if ( o.o_bd && o.o_bd->be_search ) {
495 #ifdef SLAP_OPATTRS
496                         r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
497 #endif /* SLAP_OPATTRS */
498                         (void)o.o_bd->be_search( &o, &r );
499                 }
500
501 cleanup:;
502                 if ( id ) {
503                         slap_op_groups_free( &o );
504                 }
505                 if ( o.ors_filter ) {
506                         filter_free_x( &o, o.ors_filter );
507                 }
508                 if ( o.ors_attrs && o.ors_attrs != rs->sr_attrs
509                                 && o.ors_attrs != slap_anlist_no_attrs )
510                 {
511                         op->o_tmpfree( o.ors_attrs, op->o_tmpmemctx );
512                 }
513                 if ( !BER_BVISNULL( &o.o_req_dn ) ) {
514                         op->o_tmpfree( o.o_req_dn.bv_val, op->o_tmpmemctx );
515                 }
516                 if ( !BER_BVISNULL( &o.o_req_ndn ) ) {
517                         op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx );
518                 }
519                 assert( BER_BVISNULL( &o.ors_filterstr )
520                         || o.ors_filterstr.bv_val != lud->lud_filter );
521                 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
522                 ldap_free_urldesc( lud );
523         }
524
525         rs->sr_entry = e;
526         rs->sr_flags = e_flags;
527
528         return SLAP_CB_CONTINUE;
529 }
530
531 static int
532 dynlist_sc_save_entry( Operation *op, SlapReply *rs )
533 {
534         /* save the entry in the private field of the callback,
535          * so it doesn't get freed (it's temporary!) */
536         if ( rs->sr_entry != NULL ) {
537                 dynlist_sc_t    *dlc = (dynlist_sc_t *)op->o_callback->sc_private;
538                 dlc->dlc_e = rs->sr_entry;
539                 rs->sr_entry = NULL;
540         }
541
542         return 0;
543 }
544
545 static int
546 dynlist_compare( Operation *op, SlapReply *rs )
547 {
548         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
549         dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private;
550         Operation o = *op;
551         Entry *e = NULL;
552
553         for ( ; dli != NULL; dli = dli->dli_next ) {
554                 if ( op->oq_compare.rs_ava->aa_desc == dli->dli_member_ad ) {
555                         /* This compare is for one of the attributes we're
556                          * interested in. We'll use slapd's existing dyngroup
557                          * evaluator to get the answer we want.
558                          */
559                         struct berval *id = NULL;
560
561                         o.o_do_not_cache = 1;
562
563                         if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn,
564                                 ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS ) {
565                                 o.o_dn = *id;
566                                 o.o_ndn = *id;
567                                 o.o_groups = NULL; /* authz changed, invalidate cached groups */
568                         }
569                         rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn,
570                                 &o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad );
571                         switch ( rs->sr_err ) {
572                         case LDAP_SUCCESS:
573                                 rs->sr_err = LDAP_COMPARE_TRUE;
574                                 break;
575
576                         case LDAP_NO_SUCH_OBJECT:
577                                 /* NOTE: backend_group() returns noSuchObject
578                                  * if op_ndn does not exist; however, since
579                                  * dynamic list expansion means that the
580                                  * member attribute is virtually present, the
581                                  * non-existence of the asserted value implies
582                                  * the assertion is FALSE rather than
583                                  * UNDEFINED */
584                                 rs->sr_err = LDAP_COMPARE_FALSE;
585                                 break;
586                         }
587
588                         if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx );
589
590                         return SLAP_CB_CONTINUE;
591                 }
592         }
593
594         if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) !=
595                 LDAP_SUCCESS || e == NULL ) {
596                 return SLAP_CB_CONTINUE;
597         }
598         if ( ad_dgIdentity ) {
599                 Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity );
600                 if ( id ) {
601                         o.o_dn = id->a_vals[0];
602                         o.o_ndn = id->a_nvals[0];
603                         o.o_groups = NULL;
604                 }
605         }
606         dli = (dynlist_info_t *)on->on_bi.bi_private;
607         for ( ; dli != NULL && rs->sr_err != LDAP_COMPARE_TRUE; dli = dli->dli_next ) {
608                 Attribute       *a;
609                 slap_callback   cb;
610                 SlapReply       r = { REP_SEARCH };
611                 AttributeName   an[2];
612                 int             rc;
613                 dynlist_sc_t    dlc = { 0 };
614
615                 if ( !is_entry_objectclass_or_sub( e, dli->dli_oc ))
616                         continue;
617
618                 /* if the entry has the right objectClass, generate
619                  * the dynamic list and compare */
620                 dlc.dlc_dli = dli;
621                 cb.sc_private = &dlc;
622                 cb.sc_response = dynlist_sc_save_entry;
623                 cb.sc_cleanup = NULL;
624                 cb.sc_next = NULL;
625                 o.o_callback = &cb;
626
627                 o.o_tag = LDAP_REQ_SEARCH;
628                 o.ors_limit = NULL;
629                 o.ors_tlimit = SLAP_NO_LIMIT;
630                 o.ors_slimit = SLAP_NO_LIMIT;
631
632                 o.o_bd = select_backend( &o.o_req_ndn, 1 );
633                 if ( !o.o_bd || !o.o_bd->be_search ) {
634                         goto release;
635                 }
636
637                 BER_BVSTR( &o.ors_filterstr, "(objectClass=*)" );
638                 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
639                 if ( o.ors_filter == NULL ) {
640                         /* FIXME: error? */
641                         goto release;
642                 }
643
644                 o.ors_scope = LDAP_SCOPE_BASE;
645                 o.ors_deref = LDAP_DEREF_NEVER;
646                 an[0].an_name = op->orc_ava->aa_desc->ad_cname;
647                 an[0].an_desc = op->orc_ava->aa_desc;
648                 BER_BVZERO( &an[1].an_name );
649                 o.ors_attrs = an;
650                 o.ors_attrsonly = 0;
651
652                 o.o_acl_priv = ACL_COMPARE;
653
654                 rc = o.o_bd->be_search( &o, &r );
655                 filter_free_x( &o, o.ors_filter );
656
657                 if ( o.o_dn.bv_val != op->o_dn.bv_val ) {
658                         slap_op_groups_free( &o );
659                 }
660
661                 if ( rc != 0 ) {
662                         goto release;
663                 }
664
665                 if ( dlc.dlc_e != NULL ) {
666                         r.sr_entry = dlc.dlc_e;
667                 }
668
669                 if ( r.sr_err != LDAP_SUCCESS || r.sr_entry == NULL ) {
670                         /* error? */
671                         goto release;
672                 }
673
674                 for ( a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
675                         a != NULL;
676                         a = attrs_find( a->a_next, op->orc_ava->aa_desc ) )
677                 {
678                         /* if we're here, we got a match... */
679                         rs->sr_err = LDAP_COMPARE_FALSE;
680
681                         if ( value_find_ex( op->orc_ava->aa_desc,
682                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
683                                         SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
684                                 a->a_nvals, &op->orc_ava->aa_value, op->o_tmpmemctx ) == 0 )
685                         {
686                                 rs->sr_err = LDAP_COMPARE_TRUE;
687                                 break;
688                         }
689                 }
690
691                 if ( r.sr_flags & REP_ENTRY_MUSTBEFREED ) {
692                         entry_free( r.sr_entry );
693                 }
694         }
695
696 release:;
697         if ( e != NULL ) {
698                 overlay_entry_release_ov( &o, e, 0, on );
699         }
700
701         return SLAP_CB_CONTINUE;
702 }
703
704 static int
705 dynlist_response( Operation *op, SlapReply *rs )
706 {
707         dynlist_info_t  *dli;
708
709         switch ( op->o_tag ) {
710         case LDAP_REQ_SEARCH:
711                 if ( rs->sr_type == REP_SEARCH && !get_manageDSAit( op ) )
712                 {
713                         int     rc = LDAP_OTHER;
714
715                         for ( dli = dynlist_is_dynlist_next( op, rs, NULL );
716                                 dli;
717                                 dli = dynlist_is_dynlist_next( op, rs, dli ) )
718                         {
719                                 rc = dynlist_prepare_entry( op, rs, dli );
720                         }
721
722                         if ( rc != LDAP_OTHER ) {
723                                 return rc;
724                         }
725                 }
726                 break;
727
728         case LDAP_REQ_COMPARE:
729                 switch ( rs->sr_err ) {
730                 /* NOTE: we waste a few cycles running the dynamic list
731                  * also when the result is FALSE, which occurs if the
732                  * dynamic entry itself contains the AVA attribute  */
733                 /* FIXME: this approach is less than optimal; a dedicated
734                  * compare op should be implemented, that fetches the
735                  * entry, checks if it has the appropriate objectClass
736                  * and, in case, runs a compare thru all the URIs,
737                  * stopping at the first positive occurrence; see ITS#3756 */
738                 case LDAP_COMPARE_FALSE:
739                 case LDAP_NO_SUCH_ATTRIBUTE:
740                         return dynlist_compare( op, rs );
741                 }
742                 break;
743
744         default:
745                 break;
746         }
747
748         return SLAP_CB_CONTINUE;
749 }
750
751 static int
752 dynlist_build_def_filter( dynlist_info_t *dli )
753 {
754         char    *ptr;
755
756         dli->dli_default_filter.bv_len = STRLENOF( "(!(objectClass=" "))" )
757                 + dli->dli_oc->soc_cname.bv_len;
758         dli->dli_default_filter.bv_val = ch_malloc( dli->dli_default_filter.bv_len + 1 );
759         if ( dli->dli_default_filter.bv_val == NULL ) {
760                 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: malloc failed.\n",
761                         0, 0, 0 );
762                 return -1;
763         }
764
765         ptr = lutil_strcopy( dli->dli_default_filter.bv_val, "(!(objectClass=" );
766         ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
767         ptr = lutil_strcopy( ptr, "))" );
768
769         assert( dli->dli_default_filter.bv_len == ptr - dli->dli_default_filter.bv_val );
770
771         return 0;
772 }
773
774 #ifdef OL_2_2_COMPAT
775 static int
776 dynlist_db_config(
777         BackendDB       *be,
778         const char      *fname,
779         int             lineno,
780         int             argc,
781         char            **argv )
782 {
783         slap_overinst   *on = (slap_overinst *)be->bd_info;
784
785         int             rc = 0;
786
787         if ( strcasecmp( argv[0], "dynlist-attrset" ) == 0 ) {
788                 dynlist_info_t          **dlip;
789                 ObjectClass             *oc;
790                 AttributeDescription    *ad = NULL,
791                                         *member_ad = NULL;
792                 const char              *text;
793
794                 if ( argc < 3 || argc > 4 ) {
795                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
796                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
797                                 "invalid arg number #%d.\n",
798                                 fname, lineno, argc );
799                         return 1;
800                 }
801
802                 oc = oc_find( argv[1] );
803                 if ( oc == NULL ) {
804                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
805                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
806                                 "unable to find ObjectClass \"%s\"\n",
807                                 fname, lineno, argv[ 1 ] );
808                         return 1;
809                 }
810
811                 rc = slap_str2ad( argv[2], &ad, &text );
812                 if ( rc != LDAP_SUCCESS ) {
813                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
814                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
815                                 "unable to find AttributeDescription \"%s\"\n",
816                                 fname, lineno, argv[2] );
817                         return 1;
818                 }
819
820                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
821                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
822                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
823                                 "AttributeDescription \"%s\" "
824                                 "must be a subtype of \"labeledURI\"\n",
825                                 fname, lineno, argv[2] );
826                         return 1;
827                 }
828
829                 if ( argc == 4 ) {
830                         rc = slap_str2ad( argv[3], &member_ad, &text );
831                         if ( rc != LDAP_SUCCESS ) {
832                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
833                                         "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
834                                         "unable to find AttributeDescription \"%s\"\n",
835                                         fname, lineno, argv[3] );
836                                 return 1;
837                         }
838                 }
839
840                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
841                         *dlip; dlip = &(*dlip)->dli_next )
842                 {
843                         /* The same URL attribute / member attribute pair
844                          * cannot be repeated */
845                         if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) {
846                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
847                                         "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
848                                         "URL attributeDescription \"%s\" already mapped.\n",
849                                         fname, lineno, ad->ad_cname.bv_val );
850 #if 0
851                                 /* make it a warning... */
852                                 return 1;
853 #endif
854                         }
855                 }
856
857                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
858                 (*dlip)->dli_oc = oc;
859                 (*dlip)->dli_ad = ad;
860                 (*dlip)->dli_member_ad = member_ad;
861
862                 if ( dynlist_build_def_filter( *dlip ) ) {
863                         ch_free( *dlip );
864                         *dlip = NULL;
865                         return 1;
866                 }
867
868         /* allow dyngroup syntax */
869         } else if ( strcasecmp( argv[0], "dynlist-attrpair" ) == 0 ) {
870                 dynlist_info_t          **dlip;
871                 ObjectClass             *oc;
872                 AttributeDescription    *ad = NULL,
873                                         *member_ad = NULL;
874                 const char              *text;
875
876                 if ( argc != 3 ) {
877                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
878                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
879                                 "invalid arg number #%d.\n",
880                                 fname, lineno, argc );
881                         return 1;
882                 }
883
884                 oc = oc_find( "groupOfURLs" );
885                 if ( oc == NULL ) {
886                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
887                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
888                                 "unable to find default ObjectClass \"groupOfURLs\"\n",
889                                 fname, lineno, 0 );
890                         return 1;
891                 }
892
893                 rc = slap_str2ad( argv[1], &member_ad, &text );
894                 if ( rc != LDAP_SUCCESS ) {
895                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
896                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
897                                 "unable to find AttributeDescription \"%s\"\n",
898                                 fname, lineno, argv[1] );
899                         return 1;
900                 }
901
902                 rc = slap_str2ad( argv[2], &ad, &text );
903                 if ( rc != LDAP_SUCCESS ) {
904                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
905                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
906                                 "unable to find AttributeDescription \"%s\"\n",
907                                 fname, lineno, argv[2] );
908                         return 1;
909                 }
910
911                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
912                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
913                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
914                                 "AttributeDescription \"%s\" "
915                                 "must be a subtype of \"labeledURI\"\n",
916                                 fname, lineno, argv[2] );
917                         return 1;
918                 }
919
920                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
921                         *dlip; dlip = &(*dlip)->dli_next )
922                 {
923                         /* The same URL attribute / member attribute pair
924                          * cannot be repeated */
925                         if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) {
926                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
927                                         "\"dynlist-attrpair <member-ad> <URL-ad>\": "
928                                         "URL attributeDescription \"%s\" already mapped.\n",
929                                         fname, lineno, ad->ad_cname.bv_val );
930 #if 0
931                                 /* make it a warning... */
932                                 return 1;
933 #endif
934                         }
935                 }
936
937                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
938                 (*dlip)->dli_oc = oc;
939                 (*dlip)->dli_ad = ad;
940                 (*dlip)->dli_member_ad = member_ad;
941
942                 if ( dynlist_build_def_filter( *dlip ) ) {
943                         ch_free( *dlip );
944                         *dlip = NULL;
945                         return 1;
946                 }
947
948         } else {
949                 rc = SLAP_CONF_UNKNOWN;
950         }
951
952         return rc;
953 }
954
955 #else
956 enum {
957         DL_ATTRSET = 1,
958         DL_ATTRPAIR,
959         DL_ATTRPAIR_COMPAT,
960         DL_LAST
961 };
962
963 static ConfigDriver     dl_cfgen;
964
965 static ConfigTable dlcfg[] = {
966         { "dynlist-attrset", "group-oc> <URL-ad> <member-ad",
967                 3, 4, 0, ARG_MAGIC|DL_ATTRSET, dl_cfgen,
968                 "( OLcfgOvAt:8.1 NAME 'olcDLattrSet' "
969                         "DESC 'Dynamic list: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
970                         "EQUALITY caseIgnoreMatch "
971                         "SYNTAX OMsDirectoryString "
972                         "X-ORDERED 'VALUES' )",
973                         NULL, NULL },
974         { "dynlist-attrpair", "member-ad> <URL-ad",
975                 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR, dl_cfgen,
976                         NULL, NULL, NULL },
977 #ifdef TAKEOVER_DYNGROUP
978         { "attrpair", "member-ad> <URL-ad",
979                 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR_COMPAT, dl_cfgen,
980                         NULL, NULL, NULL },
981 #endif
982         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
983 };
984
985 static ConfigOCs dlocs[] = {
986         { "( OLcfgOvOc:8.1 "
987                 "NAME 'olcDynamicList' "
988                 "DESC 'Dynamic list configuration' "
989                 "SUP olcOverlayConfig "
990                 "MAY olcDLattrSet )",
991                 Cft_Overlay, dlcfg, NULL, NULL },
992         { NULL, 0, NULL }
993 };
994
995 static int
996 dl_cfgen( ConfigArgs *c )
997 {
998         slap_overinst   *on = (slap_overinst *)c->bi;
999         dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private;
1000
1001         int             rc = 0, i;
1002
1003         if ( c->op == SLAP_CONFIG_EMIT ) {
1004                 switch( c->type ) {
1005                 case DL_ATTRSET:
1006                         for ( i = 0; dli; i++, dli = dli->dli_next ) {
1007                                 struct berval   bv;
1008                                 char            *ptr = c->cr_msg;
1009
1010                                 assert( dli->dli_oc != NULL );
1011                                 assert( dli->dli_ad != NULL );
1012
1013                                 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1014                                         SLAP_X_ORDERED_FMT "%s %s", i,
1015                                         dli->dli_oc->soc_cname.bv_val,
1016                                         dli->dli_ad->ad_cname.bv_val );
1017
1018                                 if ( dli->dli_member_ad != NULL ) {
1019                                         ptr[ 0 ] = ' ';
1020                                         ptr++;
1021                                         ptr = lutil_strcopy( ptr, dli->dli_member_ad->ad_cname.bv_val );
1022                                 }
1023
1024                                 bv.bv_val = c->cr_msg;
1025                                 bv.bv_len = ptr - bv.bv_val;
1026                                 value_add_one( &c->rvalue_vals, &bv );
1027                         }
1028                         break;
1029
1030                 case DL_ATTRPAIR_COMPAT:
1031                 case DL_ATTRPAIR:
1032                         rc = 1;
1033                         break;
1034
1035                 default:
1036                         rc = 1;
1037                         break;
1038                 }
1039
1040                 return rc;
1041
1042         } else if ( c->op == LDAP_MOD_DELETE ) {
1043                 switch( c->type ) {
1044                 case DL_ATTRSET:
1045                         if ( c->valx < 0 ) {
1046                                 dynlist_info_t  *dli_next;
1047
1048                                 for ( dli_next = dli; dli_next; dli = dli_next ) {
1049                                         dli_next = dli->dli_next;
1050
1051                                         ch_free( dli->dli_default_filter.bv_val );
1052                                         ch_free( dli );
1053                                 }
1054
1055                                 on->on_bi.bi_private = NULL;
1056
1057                         } else {
1058                                 dynlist_info_t  **dlip;
1059
1060                                 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1061                                         i < c->valx; i++ )
1062                                 {
1063                                         if ( *dlip == NULL ) {
1064                                                 return 1;
1065                                         }
1066                                         dlip = &(*dlip)->dli_next;
1067                                 }
1068
1069                                 dli = *dlip;
1070                                 *dlip = dli->dli_next;
1071                                 ch_free( dli->dli_default_filter.bv_val );
1072                                 ch_free( dli );
1073
1074                                 dli = (dynlist_info_t *)on->on_bi.bi_private;
1075                         }
1076                         break;
1077
1078                 case DL_ATTRPAIR_COMPAT:
1079                 case DL_ATTRPAIR:
1080                         rc = 1;
1081                         break;
1082
1083                 default:
1084                         rc = 1;
1085                         break;
1086                 }
1087
1088                 return rc;
1089         }
1090
1091         switch( c->type ) {
1092         case DL_ATTRSET: {
1093                 dynlist_info_t          **dlip,
1094                                         *dli_next = NULL;
1095                 ObjectClass             *oc = NULL;
1096                 AttributeDescription    *ad = NULL,
1097                                         *member_ad = NULL;
1098                 const char              *text;
1099
1100                 oc = oc_find( c->argv[ 1 ] );
1101                 if ( oc == NULL ) {
1102                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1103                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1104                                 "unable to find ObjectClass \"%s\"",
1105                                 c->argv[ 1 ] );
1106                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1107                                 c->log, c->cr_msg, 0 );
1108                         return 1;
1109                 }
1110
1111                 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
1112                 if ( rc != LDAP_SUCCESS ) {
1113                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1114                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1115                                 "unable to find AttributeDescription \"%s\"",
1116                                 c->argv[ 2 ] );
1117                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1118                                 c->log, c->cr_msg, 0 );
1119                         return 1;
1120                 }
1121
1122                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1123                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1124                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1125                                 "AttributeDescription \"%s\" "
1126                                 "must be a subtype of \"labeledURI\"",
1127                                 c->argv[ 2 ] );
1128                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1129                                 c->log, c->cr_msg, 0 );
1130                         return 1;
1131                 }
1132
1133                 if ( c->argc == 4 ) {
1134                         rc = slap_str2ad( c->argv[ 3 ], &member_ad, &text );
1135                         if ( rc != LDAP_SUCCESS ) {
1136                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1137                                         "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1138                                         "unable to find AttributeDescription \"%s\"\n",
1139                                         c->argv[ 3 ] );
1140                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1141                                         c->log, c->cr_msg, 0 );
1142                                 return 1;
1143                         }
1144                 }
1145
1146                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1147                         *dlip; dlip = &(*dlip)->dli_next )
1148                 {
1149                         /* The same URL attribute / member attribute pair
1150                          * cannot be repeated */
1151                         if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) {
1152                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1153                                         "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1154                                         "URL attributeDescription \"%s\" already mapped.\n",
1155                                         ad->ad_cname.bv_val );
1156                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1157                                         c->log, c->cr_msg, 0 );
1158 #if 0
1159                                 /* make it a warning... */
1160                                 return 1;
1161 #endif
1162                         }
1163                 }
1164
1165                 if ( c->valx > 0 ) {
1166                         int     i;
1167
1168                         for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1169                                 i < c->valx; i++ )
1170                         {
1171                                 if ( *dlip == NULL ) {
1172                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1173                                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1174                                                 "invalid index {%d}\n",
1175                                                 c->valx );
1176                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1177                                                 c->log, c->cr_msg, 0 );
1178                                         return 1;
1179                                 }
1180                                 dlip = &(*dlip)->dli_next;
1181                         }
1182                         dli_next = *dlip;
1183
1184                 } else {
1185                         for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1186                                 *dlip; dlip = &(*dlip)->dli_next )
1187                                 /* goto last */;
1188                 }
1189
1190                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1191
1192                 (*dlip)->dli_oc = oc;
1193                 (*dlip)->dli_ad = ad;
1194                 (*dlip)->dli_member_ad = member_ad;
1195                 (*dlip)->dli_next = dli_next;
1196
1197                 rc = dynlist_build_def_filter( *dlip );
1198
1199                 } break;
1200
1201         case DL_ATTRPAIR_COMPAT:
1202                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1203                         "warning: \"attrpair\" only supported for limited "
1204                         "backward compatibility with overlay \"dyngroup\"" );
1205                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1206                 /* fallthru */
1207
1208         case DL_ATTRPAIR: {
1209                 dynlist_info_t          **dlip;
1210                 ObjectClass             *oc = NULL;
1211                 AttributeDescription    *ad = NULL,
1212                                         *member_ad = NULL;
1213                 const char              *text;
1214
1215                 oc = oc_find( "groupOfURLs" );
1216                 if ( oc == NULL ) {
1217                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1218                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1219                                 "unable to find default ObjectClass \"groupOfURLs\"" );
1220                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1221                                 c->log, c->cr_msg, 0 );
1222                         return 1;
1223                 }
1224
1225                 rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text );
1226                 if ( rc != LDAP_SUCCESS ) {
1227                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1228                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1229                                 "unable to find AttributeDescription \"%s\"",
1230                                 c->argv[ 1 ] );
1231                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1232                                 c->log, c->cr_msg, 0 );
1233                         return 1;
1234                 }
1235
1236                 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
1237                 if ( rc != LDAP_SUCCESS ) {
1238                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1239                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1240                                 "unable to find AttributeDescription \"%s\"\n",
1241                                 c->argv[ 2 ] );
1242                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1243                                 c->log, c->cr_msg, 0 );
1244                         return 1;
1245                 }
1246
1247                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1248                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1249                                 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1250                                 "AttributeDescription \"%s\" "
1251                                 "must be a subtype of \"labeledURI\"",
1252                                 c->argv[ 2 ] );
1253                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1254                                 c->log, c->cr_msg, 0 );
1255                         return 1;
1256                 }
1257
1258                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1259                         *dlip; dlip = &(*dlip)->dli_next )
1260                 {
1261                         /* The same URL attribute / member attribute pair
1262                          * cannot be repeated */
1263                         if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) {
1264                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1265                                         "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1266                                         "URL attributeDescription \"%s\" already mapped.\n",
1267                                         ad->ad_cname.bv_val );
1268                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1269                                         c->log, c->cr_msg, 0 );
1270 #if 0
1271                                 /* make it a warning... */
1272                                 return 1;
1273 #endif
1274                         }
1275                 }
1276
1277                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1278
1279                 (*dlip)->dli_oc = oc;
1280                 (*dlip)->dli_ad = ad;
1281                 (*dlip)->dli_member_ad = member_ad;
1282
1283                 rc = dynlist_build_def_filter( *dlip );
1284
1285                 } break;
1286
1287         default:
1288                 rc = 1;
1289                 break;
1290         }
1291
1292         return rc;
1293 }
1294 #endif
1295
1296 static int
1297 dynlist_db_open(
1298         BackendDB       *be,
1299         ConfigReply     *cr )
1300 {
1301         slap_overinst           *on = (slap_overinst *) be->bd_info;
1302         dynlist_info_t          *dli = (dynlist_info_t *)on->on_bi.bi_private;
1303         ObjectClass             *oc = NULL;
1304         AttributeDescription    *ad = NULL;
1305         const char      *text;
1306         int rc;
1307
1308         if ( dli == NULL ) {
1309                 dli = ch_calloc( 1, sizeof( dynlist_info_t ) );
1310                 on->on_bi.bi_private = (void *)dli;
1311         }
1312
1313         for ( ; dli; dli = dli->dli_next ) {
1314                 if ( dli->dli_oc == NULL ) {
1315                         if ( oc == NULL ) {
1316                                 oc = oc_find( "groupOfURLs" );
1317                                 if ( oc == NULL ) {
1318                                         sprintf( cr->msg, "unable to fetch objectClass \"groupOfURLs\"" );
1319                                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1320                                         return 1;
1321                                 }
1322                         }
1323
1324                         dli->dli_oc = oc;
1325                 }
1326
1327                 if ( dli->dli_ad == NULL ) {
1328                         if ( ad == NULL ) {
1329                                 rc = slap_str2ad( "memberURL", &ad, &text );
1330                                 if ( rc != LDAP_SUCCESS ) {
1331                                         sprintf( cr->msg, "unable to fetch attributeDescription \"memberURL\": %d (%s)",
1332                                                 rc, text );
1333                                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1334                                         return 1;
1335                                 }
1336                         }
1337                 
1338                         dli->dli_ad = ad;                       
1339                 }
1340
1341                 if ( BER_BVISNULL( &dli->dli_default_filter ) ) {
1342                         rc = dynlist_build_def_filter( dli );
1343                         if ( rc != 0 ) {
1344                                 return rc;
1345                         }
1346                 }
1347         }
1348
1349         rc = slap_str2ad( "dgIdentity", &ad_dgIdentity, &text );
1350         if ( rc != LDAP_SUCCESS ) {
1351                 snprintf( cr->msg, sizeof( cr->msg),
1352                         "unable to fetch attributeDescription \"dgIdentity\": %d (%s)",
1353                         rc, text );
1354                 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 );
1355                 /* Just a warning */
1356         }
1357
1358         return 0;
1359 }
1360
1361 static int
1362 dynlist_db_destroy(
1363         BackendDB       *be,
1364         ConfigReply     *cr )
1365 {
1366         slap_overinst   *on = (slap_overinst *) be->bd_info;
1367
1368         if ( on->on_bi.bi_private ) {
1369                 dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private,
1370                                 *dli_next;
1371
1372                 for ( dli_next = dli; dli_next; dli = dli_next ) {
1373                         dli_next = dli->dli_next;
1374
1375                         ch_free( dli->dli_default_filter.bv_val );
1376                         ch_free( dli );
1377                 }
1378         }
1379
1380         return 0;
1381 }
1382
1383 static slap_overinst    dynlist = { { NULL } };
1384 #ifdef TAKEOVER_DYNGROUP
1385 static char             *obsolete_names[] = {
1386         "dyngroup",
1387         NULL
1388 };
1389 #endif
1390
1391 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1392 static
1393 #endif /* SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC */
1394 int
1395 dynlist_initialize(void)
1396 {
1397 #ifndef OL_2_2_COMPAT
1398         int     rc = 0;
1399 #endif
1400
1401         dynlist.on_bi.bi_type = "dynlist";
1402
1403 #ifdef TAKEOVER_DYNGROUP
1404         /* makes dynlist incompatible with dyngroup */
1405         dynlist.on_bi.bi_obsolete_names = obsolete_names;
1406 #endif
1407
1408 #ifdef OL_2_2_COMPAT
1409         dynlist.on_bi.bi_db_config = dynlist_db_config;
1410 #else
1411         dynlist.on_bi.bi_db_config = config_generic_wrapper;
1412 #endif
1413         dynlist.on_bi.bi_db_open = dynlist_db_open;
1414         dynlist.on_bi.bi_db_destroy = dynlist_db_destroy;
1415
1416         dynlist.on_response = dynlist_response;
1417
1418 #ifndef OL_2_2_COMPAT
1419         dynlist.on_bi.bi_cf_ocs = dlocs;
1420
1421         rc = config_register_schema( dlcfg, dlocs );
1422         if ( rc ) {
1423                 return rc;
1424         }
1425 #endif
1426
1427         return overlay_register( &dynlist );
1428 }
1429
1430 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1431 int
1432 init_module( int argc, char *argv[] )
1433 {
1434         return dynlist_initialize();
1435 }
1436 #endif
1437
1438 #endif /* SLAPD_OVER_DYNLIST */