]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/dynlist.c
ITS#5898
[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-2009 The OpenLDAP Foundation.
6  * Portions Copyright 2004-2005 Pierangelo Masarati.
7  * Portions Copyright 2008 Emmanuel Dreyfus.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by Pierangelo Masarati
20  * for SysNet s.n.c., for inclusion in OpenLDAP Software.
21  */
22
23 #include "portable.h"
24
25 #ifdef SLAPD_OVER_DYNLIST
26
27 #if LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR > 3
28 #if SLAPD_OVER_DYNGROUP != SLAPD_MOD_STATIC
29 #define TAKEOVER_DYNGROUP
30 #endif
31 #else
32 #if LDAP_VENDOR_VERSION_MINOR < 3
33 #define OL_2_2_COMPAT
34 #endif
35 #endif
36
37 #include <stdio.h>
38
39 #include <ac/string.h>
40
41 #include "slap.h"
42 #ifndef OL_2_2_COMPAT
43 #include "config.h"
44 #endif
45 #include "lutil.h"
46
47 /* FIXME: the code differs if SLAP_OPATTRS is defined or not;
48  * SLAP_OPATTRS is not defined in 2.2 yet, while this overlay
49  * expects HEAD code at least later than August 6, 2004. */
50 /* FIXME: slap_anlist_no_attrs was introduced in 2.3; here it
51  * is anticipated to allow using this overlay with 2.2. */
52
53 #ifdef OL_2_2_COMPAT
54 static AttributeName anlist_no_attrs[] = {
55         { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL },
56         { BER_BVNULL, NULL, 0, NULL }
57 };
58
59 static AttributeName *slap_anlist_no_attrs = anlist_no_attrs;
60 #endif
61
62 static AttributeDescription *ad_dgIdentity, *ad_dgAuthz;
63
64 typedef struct dynlist_map_t {
65         AttributeDescription    *dlm_member_ad;
66         AttributeDescription    *dlm_mapped_ad;
67         struct dynlist_map_t    *dlm_next;
68 } dynlist_map_t;
69
70 typedef struct dynlist_info_t {
71         ObjectClass             *dli_oc;
72         AttributeDescription    *dli_ad;
73         struct dynlist_map_t    *dli_dlm;
74         struct berval           dli_uri;
75         LDAPURLDesc             *dli_lud;
76         struct berval           dli_uri_nbase;
77         Filter                  *dli_uri_filter;
78         struct berval           dli_default_filter;
79         struct dynlist_info_t   *dli_next;
80 } dynlist_info_t;
81
82 #define DYNLIST_USAGE \
83         "\"dynlist-attrset <oc> [uri] <URL-ad> [[<mapped-ad>:]<member-ad> ...]\": "
84
85 static dynlist_info_t *
86 dynlist_is_dynlist_next( Operation *op, SlapReply *rs, dynlist_info_t *old_dli )
87 {
88         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
89         dynlist_info_t  *dli;
90
91         Attribute       *a;
92
93         if ( old_dli == NULL ) {
94                 dli = (dynlist_info_t *)on->on_bi.bi_private;
95
96         } else {
97                 dli = old_dli->dli_next;
98         }
99
100         a = attrs_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
101         if ( a == NULL ) {
102                 /* FIXME: objectClass must be present; for non-storage
103                  * backends, like back-ldap, it needs to be added
104                  * to the requested attributes */
105                 return NULL;
106         }
107
108         for ( ; dli; dli = dli->dli_next ) {
109                 if ( dli->dli_lud != NULL ) {
110                         /* check base and scope */
111                         if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
112                                 int d = rs->sr_entry->e_nname.bv_len - dli->dli_uri_nbase.bv_len;
113
114                                 if ( d < 0 ) {
115                                         continue;
116                                 }
117
118                                 if ( !dnIsSuffix( &rs->sr_entry->e_nname, &dli->dli_uri_nbase ) ) {
119                                         continue;
120                                 }
121
122                                 switch ( dli->dli_lud->lud_scope ) {
123                                 case LDAP_SCOPE_BASE:
124                                         if ( d != 0 ) {
125                                                 continue;
126                                         }
127                                         break;
128
129                                 case LDAP_SCOPE_ONELEVEL: {
130                                         struct berval pdn;
131
132                                         dnParent( &rs->sr_entry->e_nname, &pdn );
133                                         if ( pdn.bv_len != dli->dli_uri_nbase.bv_len ) {
134                                                 continue;
135                                         }
136                                         } break;
137
138                                 case LDAP_SCOPE_SUBORDINATE:
139                                         if ( d == 0 ) {
140                                                 continue;
141                                         }
142                                         break;
143
144                                 case LDAP_SCOPE_SUBTREE:
145                                 case LDAP_SCOPE_DEFAULT:
146                                         break;
147
148                                 default:
149                                         continue;
150                                 }
151                         }
152
153                         /* check filter */
154                         if ( dli->dli_uri_filter && test_filter( op, rs->sr_entry, dli->dli_uri_filter ) != LDAP_COMPARE_TRUE ) {
155                                 continue;
156                         }
157                 }
158
159                 if ( attr_valfind( a,
160                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
161                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
162                                 &dli->dli_oc->soc_cname, NULL,
163                                 op->o_tmpmemctx ) == 0 )
164                 {
165                         return dli;
166                 }
167         }
168
169         return NULL;
170 }
171
172 static int
173 dynlist_make_filter( Operation *op, struct berval *oldf, struct berval *newf )
174 {
175         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
176         dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private;
177
178         char            *ptr;
179
180         assert( oldf != NULL );
181         assert( newf != NULL );
182         assert( !BER_BVISNULL( oldf ) );
183         assert( !BER_BVISEMPTY( oldf ) );
184
185         newf->bv_len = STRLENOF( "(&(!(objectClass=" "))" ")" )
186                 + dli->dli_oc->soc_cname.bv_len + oldf->bv_len;
187         newf->bv_val = op->o_tmpalloc( newf->bv_len + 1, op->o_tmpmemctx );
188         if ( newf->bv_val == NULL ) {
189                 return -1;
190         }
191         ptr = lutil_strcopy( newf->bv_val, "(&(!(objectClass=" );
192         ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
193         ptr = lutil_strcopy( ptr, "))" );
194         ptr = lutil_strcopy( ptr, oldf->bv_val );
195         ptr = lutil_strcopy( ptr, ")" );
196         newf->bv_len = ptr - newf->bv_val;
197
198         return 0;
199 }
200
201 typedef struct dynlist_sc_t {
202         dynlist_info_t    *dlc_dli;
203         Entry           *dlc_e;
204 } dynlist_sc_t;
205
206 static int
207 dynlist_sc_update( Operation *op, SlapReply *rs )
208 {
209         Entry                   *e;
210         Attribute               *a;
211         int                     opattrs,
212                                 userattrs;
213         AccessControlState      acl_state = ACL_STATE_INIT;
214
215         dynlist_sc_t            *dlc;
216         dynlist_map_t           *dlm;
217
218         if ( rs->sr_type != REP_SEARCH ) {
219                 return 0;
220         }
221
222         dlc = (dynlist_sc_t *)op->o_callback->sc_private;
223         e = dlc->dlc_e;
224
225         assert( e != NULL );
226         assert( rs->sr_entry != NULL );
227
228         /* test access to entry */
229         if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
230                                 NULL, ACL_READ, NULL ) )
231         {
232                 goto done;
233         }
234
235         /* if there is only one member_ad, and it's not mapped,
236          * consider it as old-style member listing */
237         dlm = dlc->dlc_dli->dli_dlm;
238         if ( dlm && dlm->dlm_mapped_ad == NULL && dlm->dlm_next == NULL ) {
239                 /* if access allowed, try to add values, emulating permissive
240                  * control to silently ignore duplicates */
241                 if ( access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
242                                         NULL, ACL_READ, NULL ) )
243                 {
244                         Modification    mod;
245                         const char      *text = NULL;
246                         char            textbuf[1024];
247                         struct berval   vals[ 2 ], nvals[ 2 ];
248
249                         vals[ 0 ] = rs->sr_entry->e_name;
250                         BER_BVZERO( &vals[ 1 ] );
251                         nvals[ 0 ] = rs->sr_entry->e_nname;
252                         BER_BVZERO( &nvals[ 1 ] );
253
254                         mod.sm_op = LDAP_MOD_ADD;
255                         mod.sm_desc = dlm->dlm_member_ad;
256                         mod.sm_type = dlm->dlm_member_ad->ad_cname;
257                         mod.sm_values = vals;
258                         mod.sm_nvalues = nvals;
259                         mod.sm_numvals = 1;
260
261                         (void)modify_add_values( e, &mod, /* permissive */ 1,
262                                         &text, textbuf, sizeof( textbuf ) );
263                 }
264
265                 goto done;
266         }
267
268 #ifndef SLAP_OPATTRS
269         opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
270         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
271 #else /* SLAP_OPATTRS */
272         opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
273         userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
274 #endif /* SLAP_OPATTRS */
275
276         for ( a = rs->sr_entry->e_attrs; a != NULL; a = a->a_next ) {
277                 BerVarray       vals, nvals = NULL;
278                 int             i, j,
279                                 is_oc = a->a_desc == slap_schema.si_ad_objectClass;
280
281                 /* if attribute is not requested, skip it */
282                 if ( rs->sr_attrs == NULL ) {
283                         if ( is_at_operational( a->a_desc->ad_type ) ) {
284                                 continue;
285                         }
286
287                 } else {
288                         if ( is_at_operational( a->a_desc->ad_type ) ) {
289                                 if ( !opattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
290                                 {
291                                         continue;
292                                 }
293
294                         } else {
295                                 if ( !userattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
296                                 {
297                                         continue;
298                                 }
299                         }
300                 }
301
302                 /* test access to attribute */
303                 if ( op->ors_attrsonly ) {
304                         if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL,
305                                                 ACL_READ, &acl_state ) )
306                         {
307                                 continue;
308                         }
309                 }
310
311                 /* single-value check: keep first only */
312                 if ( is_at_single_value( a->a_desc->ad_type ) ) {
313                         if ( attr_find( e->e_attrs, a->a_desc ) != NULL ) {
314                                 continue;
315                         }
316                 }
317
318                 /* test access to attribute */
319                 i = a->a_numvals;
320
321                 vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
322                 if ( a->a_nvals != a->a_vals ) {
323                         nvals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
324                 }
325
326                 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
327                         if ( is_oc ) {
328                                 ObjectClass     *soc = oc_bvfind( &a->a_vals[i] );
329
330                                 if ( soc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) {
331                                         continue;
332                                 }
333                         }
334
335                         if ( access_allowed( op, rs->sr_entry, a->a_desc,
336                                                 &a->a_nvals[i], ACL_READ, &acl_state ) )
337                         {
338                                 vals[j] = a->a_vals[i];
339                                 if ( nvals ) {
340                                         nvals[j] = a->a_nvals[i];
341                                 }
342                                 j++;
343                         }
344                 }
345
346                 /* if access allowed, try to add values, emulating permissive
347                  * control to silently ignore duplicates */
348                 if ( j != 0 ) {
349                         Modification    mod;
350                         const char      *text = NULL;
351                         char            textbuf[1024];
352                         dynlist_map_t   *dlm;
353                         AttributeDescription *ad;
354
355                         BER_BVZERO( &vals[j] );
356                         if ( nvals ) {
357                                 BER_BVZERO( &nvals[j] );
358                         }
359
360                         ad = a->a_desc;
361                         for ( dlm = dlc->dlc_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
362                                 if ( dlm->dlm_member_ad == a->a_desc ) {
363                                         if ( dlm->dlm_mapped_ad ) {
364                                                 ad = dlm->dlm_mapped_ad;
365                                         }
366                                         break;
367                                 }
368                         }
369
370                         mod.sm_op = LDAP_MOD_ADD;
371                         mod.sm_desc = ad;
372                         mod.sm_type = ad->ad_cname;
373                         mod.sm_values = vals;
374                         mod.sm_nvalues = nvals;
375                         mod.sm_numvals = j;
376
377                         (void)modify_add_values( e, &mod, /* permissive */ 1,
378                                         &text, textbuf, sizeof( textbuf ) );
379                 }
380
381                 op->o_tmpfree( vals, op->o_tmpmemctx );
382                 if ( nvals ) {
383                         op->o_tmpfree( nvals, op->o_tmpmemctx );
384                 }
385         }
386
387 done:;
388         if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
389                 entry_free( rs->sr_entry );
390                 rs->sr_entry = NULL;
391                 rs->sr_flags ^= REP_ENTRY_MUSTBEFREED;
392         }
393
394         return 0;
395 }
396         
397 static int
398 dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli )
399 {
400         Attribute       *a, *id = NULL;
401         slap_callback   cb;
402         Operation       o = *op;
403         SlapReply       r = { REP_SEARCH };
404         struct berval   *url;
405         Entry           *e;
406         slap_mask_t     e_flags;
407         int             opattrs,
408                         userattrs;
409         dynlist_sc_t    dlc = { 0 };
410         dynlist_map_t   *dlm;
411
412         a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad );
413         if ( a == NULL ) {
414                 /* FIXME: error? */
415                 return SLAP_CB_CONTINUE;
416         }
417
418 #ifndef SLAP_OPATTRS
419         opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
420         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
421 #else /* SLAP_OPATTRS */
422         opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
423         userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
424 #endif /* SLAP_OPATTRS */
425
426         /* Don't generate member list if it wasn't requested */
427         for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
428                 AttributeDescription *ad = dlm->dlm_mapped_ad ? dlm->dlm_mapped_ad : dlm->dlm_member_ad;
429                 if ( userattrs || ad_inlist( ad, rs->sr_attrs ) ) 
430                         break;
431         }
432         if ( dli->dli_dlm && !dlm )
433                 return SLAP_CB_CONTINUE;
434
435         if ( ad_dgIdentity && ( id = attrs_find( rs->sr_entry->e_attrs, ad_dgIdentity ))) {
436                 Attribute *authz = NULL;
437
438                 /* if not rootdn and dgAuthz is present,
439                  * check if user can be authorized as dgIdentity */
440                 if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
441                         && ( authz = attrs_find( rs->sr_entry->e_attrs, ad_dgAuthz ) ) )
442                 {
443                         if ( slap_sasl_matches( op, authz->a_nvals,
444                                 &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
445                         {
446                                 return SLAP_CB_CONTINUE;
447                         }
448                 }
449
450                 o.o_dn = id->a_vals[0];
451                 o.o_ndn = id->a_nvals[0];
452                 o.o_groups = NULL;
453         }
454
455         e_flags = rs->sr_flags;
456         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
457                 e = entry_dup( rs->sr_entry );
458                 e_flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
459         } else {
460                 e = rs->sr_entry;
461         }
462
463         dlc.dlc_e = e;
464         dlc.dlc_dli = dli;
465         cb.sc_private = &dlc;
466         cb.sc_response = dynlist_sc_update;
467         cb.sc_cleanup = NULL;
468         cb.sc_next = NULL;
469
470         o.o_callback = &cb;
471         o.ors_deref = LDAP_DEREF_NEVER;
472         o.ors_limit = NULL;
473         o.ors_tlimit = SLAP_NO_LIMIT;
474         o.ors_slimit = SLAP_NO_LIMIT;
475
476         for ( url = a->a_nvals; !BER_BVISNULL( url ); url++ ) {
477                 LDAPURLDesc     *lud = NULL;
478                 int             i, j;
479                 struct berval   dn;
480                 int             rc;
481
482                 BER_BVZERO( &o.o_req_dn );
483                 BER_BVZERO( &o.o_req_ndn );
484                 o.ors_filter = NULL;
485                 o.ors_attrs = NULL;
486                 BER_BVZERO( &o.ors_filterstr );
487
488                 if ( ldap_url_parse( url->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
489                         /* FIXME: error? */
490                         continue;
491                 }
492
493                 if ( lud->lud_host != NULL ) {
494                         /* FIXME: host not allowed; reject as illegal? */
495                         Debug( LDAP_DEBUG_ANY, "dynlist_prepare_entry(\"%s\"): "
496                                 "illegal URI \"%s\"\n",
497                                 e->e_name.bv_val, url->bv_val, 0 );
498                         goto cleanup;
499                 }
500
501                 if ( lud->lud_dn == NULL ) {
502                         /* note that an empty base is not honored in terms
503                          * of defaultSearchBase, because select_backend()
504                          * is not aware of the defaultSearchBase option;
505                          * this can be useful in case of a database serving
506                          * the empty suffix */
507                         BER_BVSTR( &dn, "" );
508
509                 } else {
510                         ber_str2bv( lud->lud_dn, 0, 0, &dn );
511                 }
512                 rc = dnPrettyNormal( NULL, &dn, &o.o_req_dn, &o.o_req_ndn, op->o_tmpmemctx );
513                 if ( rc != LDAP_SUCCESS ) {
514                         /* FIXME: error? */
515                         goto cleanup;
516                 }
517                 o.ors_scope = lud->lud_scope;
518
519                 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
520                         if ( dlm->dlm_mapped_ad != NULL ) {
521                                 break;
522                         }
523                 }
524
525                 if ( dli->dli_dlm && !dlm ) {
526                         /* if ( lud->lud_attrs != NULL ),
527                          * the URL should be ignored */
528                         o.ors_attrs = slap_anlist_no_attrs;
529
530                 } else if ( lud->lud_attrs == NULL ) {
531                         o.ors_attrs = rs->sr_attrs;
532
533                 } else {
534                         for ( i = 0; lud->lud_attrs[i]; i++)
535                                 /* just count */ ;
536
537                         o.ors_attrs = op->o_tmpcalloc( i + 1, sizeof( AttributeName ), op->o_tmpmemctx );
538                         for ( i = 0, j = 0; lud->lud_attrs[i]; i++) {
539                                 const char      *text = NULL;
540         
541                                 ber_str2bv( lud->lud_attrs[i], 0, 0, &o.ors_attrs[j].an_name );
542                                 o.ors_attrs[j].an_desc = NULL;
543                                 (void)slap_bv2ad( &o.ors_attrs[j].an_name, &o.ors_attrs[j].an_desc, &text );
544                                 /* FIXME: ignore errors... */
545
546                                 if ( rs->sr_attrs == NULL ) {
547                                         if ( o.ors_attrs[j].an_desc != NULL &&
548                                                         is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
549                                         {
550                                                 continue;
551                                         }
552
553                                 } else {
554                                         if ( o.ors_attrs[j].an_desc != NULL &&
555                                                         is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
556                                         {
557                                                 if ( !opattrs ) {
558                                                         continue;
559                                                 }
560
561                                                 if ( !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) ) {
562                                                         /* lookup if mapped -- linear search,
563                                                          * not very efficient unless list
564                                                          * is very short */
565                                                         for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
566                                                                 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) {
567                                                                         break;
568                                                                 }
569                                                         }
570
571                                                         if ( dlm == NULL ) {
572                                                                 continue;
573                                                         }
574                                                 }
575
576                                         } else {
577                                                 if ( !userattrs && 
578                                                                 o.ors_attrs[j].an_desc != NULL &&
579                                                                 !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
580                                                 {
581                                                         /* lookup if mapped -- linear search,
582                                                          * not very efficient unless list
583                                                          * is very short */
584                                                         for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
585                                                                 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) {
586                                                                         break;
587                                                                 }
588                                                         }
589
590                                                         if ( dlm == NULL ) {
591                                                                 continue;
592                                                         }
593                                                 }
594                                         }
595                                 }
596
597                                 j++;
598                         }
599
600                         if ( j == 0 ) {
601                                 goto cleanup;
602                         }
603                 
604                         BER_BVZERO( &o.ors_attrs[j].an_name );
605                 }
606
607                 if ( lud->lud_filter == NULL ) {
608                         ber_dupbv_x( &o.ors_filterstr,
609                                         &dli->dli_default_filter, op->o_tmpmemctx );
610
611                 } else {
612                         struct berval   flt;
613                         ber_str2bv( lud->lud_filter, 0, 0, &flt );
614                         if ( dynlist_make_filter( op, &flt, &o.ors_filterstr ) ) {
615                                 /* error */
616                                 goto cleanup;
617                         }
618                 }
619                 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
620                 if ( o.ors_filter == NULL ) {
621                         goto cleanup;
622                 }
623                 
624                 o.o_bd = select_backend( &o.o_req_ndn, 1 );
625                 if ( o.o_bd && o.o_bd->be_search ) {
626 #ifdef SLAP_OPATTRS
627                         r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
628 #endif /* SLAP_OPATTRS */
629                         (void)o.o_bd->be_search( &o, &r );
630                 }
631
632 cleanup:;
633                 if ( id ) {
634                         slap_op_groups_free( &o );
635                 }
636                 if ( o.ors_filter ) {
637                         filter_free_x( &o, o.ors_filter, 1 );
638                 }
639                 if ( o.ors_attrs && o.ors_attrs != rs->sr_attrs
640                                 && o.ors_attrs != slap_anlist_no_attrs )
641                 {
642                         op->o_tmpfree( o.ors_attrs, op->o_tmpmemctx );
643                 }
644                 if ( !BER_BVISNULL( &o.o_req_dn ) ) {
645                         op->o_tmpfree( o.o_req_dn.bv_val, op->o_tmpmemctx );
646                 }
647                 if ( !BER_BVISNULL( &o.o_req_ndn ) ) {
648                         op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx );
649                 }
650                 assert( BER_BVISNULL( &o.ors_filterstr )
651                         || o.ors_filterstr.bv_val != lud->lud_filter );
652                 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
653                 ldap_free_urldesc( lud );
654         }
655
656         rs->sr_entry = e;
657         rs->sr_flags = e_flags;
658
659         return SLAP_CB_CONTINUE;
660 }
661
662 static int
663 dynlist_sc_save_entry( Operation *op, SlapReply *rs )
664 {
665         /* save the entry in the private field of the callback,
666          * so it doesn't get freed (it's temporary!) */
667         if ( rs->sr_entry != NULL ) {
668                 dynlist_sc_t    *dlc = (dynlist_sc_t *)op->o_callback->sc_private;
669                 dlc->dlc_e = rs->sr_entry;
670                 rs->sr_entry = NULL;
671         }
672
673         return 0;
674 }
675
676 static int
677 dynlist_compare( Operation *op, SlapReply *rs )
678 {
679         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
680         dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private;
681         Operation o = *op;
682         Entry *e = NULL;
683         dynlist_map_t *dlm;
684
685         for ( ; dli != NULL; dli = dli->dli_next ) {
686                 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next )
687                         if ( op->oq_compare.rs_ava->aa_desc == dlm->dlm_member_ad )
688                                 break;
689
690                 if ( dli->dli_dlm && dlm ) {
691                         /* This compare is for one of the attributes we're
692                          * interested in. We'll use slapd's existing dyngroup
693                          * evaluator to get the answer we want.
694                          */
695                         BerVarray id = NULL, authz = NULL;
696
697                         o.o_do_not_cache = 1;
698
699                         if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn,
700                                 ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS )
701                         {
702                                 /* if not rootdn and dgAuthz is present,
703                                  * check if user can be authorized as dgIdentity */
704                                 if ( ad_dgAuthz && !BER_BVISEMPTY( id ) && !be_isroot( op )
705                                         && backend_attribute( &o, NULL, &o.o_req_ndn,
706                                                 ad_dgAuthz, &authz, ACL_READ ) == LDAP_SUCCESS )
707                                 {
708                                         
709                                         rs->sr_err = slap_sasl_matches( op, authz,
710                                                 &o.o_ndn, &o.o_ndn );
711                                         ber_bvarray_free_x( authz, op->o_tmpmemctx );
712                                         if ( rs->sr_err != LDAP_SUCCESS ) {
713                                                 goto done;
714                                         }
715                                 }
716
717                                 o.o_dn = *id;
718                                 o.o_ndn = *id;
719                                 o.o_groups = NULL; /* authz changed, invalidate cached groups */
720                         }
721
722                         rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn,
723                                 &o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad );
724                         switch ( rs->sr_err ) {
725                         case LDAP_SUCCESS:
726                                 rs->sr_err = LDAP_COMPARE_TRUE;
727                                 break;
728
729                         case LDAP_NO_SUCH_OBJECT:
730                                 /* NOTE: backend_group() returns noSuchObject
731                                  * if op_ndn does not exist; however, since
732                                  * dynamic list expansion means that the
733                                  * member attribute is virtually present, the
734                                  * non-existence of the asserted value implies
735                                  * the assertion is FALSE rather than
736                                  * UNDEFINED */
737                                 rs->sr_err = LDAP_COMPARE_FALSE;
738                                 break;
739                         }
740
741 done:;
742                         if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx );
743
744                         return SLAP_CB_CONTINUE;
745                 }
746         }
747
748         if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) !=
749                 LDAP_SUCCESS || e == NULL )
750         {
751                 return SLAP_CB_CONTINUE;
752         }
753
754         if ( ad_dgIdentity ) {
755                 Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity );
756                 if ( id ) {
757                         Attribute *authz;
758
759                         /* if not rootdn and dgAuthz is present,
760                          * check if user can be authorized as dgIdentity */
761                         if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
762                                 && ( authz = attrs_find( e->e_attrs, ad_dgAuthz ) ) )
763                         {
764                                 if ( slap_sasl_matches( op, authz->a_nvals,
765                                         &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
766                                 {
767                                         goto release;
768                                 }
769                         }
770
771                         o.o_dn = id->a_vals[0];
772                         o.o_ndn = id->a_nvals[0];
773                         o.o_groups = NULL;
774                 }
775         }
776
777         dli = (dynlist_info_t *)on->on_bi.bi_private;
778         for ( ; dli != NULL && rs->sr_err != LDAP_COMPARE_TRUE; dli = dli->dli_next ) {
779                 Attribute       *a;
780                 slap_callback   cb;
781                 SlapReply       r = { REP_SEARCH };
782                 AttributeName   an[2];
783                 int             rc;
784                 dynlist_sc_t    dlc = { 0 };
785
786                 if ( !is_entry_objectclass_or_sub( e, dli->dli_oc ))
787                         continue;
788
789                 /* if the entry has the right objectClass, generate
790                  * the dynamic list and compare */
791                 dlc.dlc_dli = dli;
792                 cb.sc_private = &dlc;
793                 cb.sc_response = dynlist_sc_save_entry;
794                 cb.sc_cleanup = NULL;
795                 cb.sc_next = NULL;
796                 o.o_callback = &cb;
797
798                 o.o_tag = LDAP_REQ_SEARCH;
799                 o.ors_limit = NULL;
800                 o.ors_tlimit = SLAP_NO_LIMIT;
801                 o.ors_slimit = SLAP_NO_LIMIT;
802
803                 o.o_bd = select_backend( &o.o_req_ndn, 1 );
804                 if ( !o.o_bd || !o.o_bd->be_search ) {
805                         goto release;
806                 }
807
808                 o.ors_filterstr = *slap_filterstr_objectClass_pres;
809                 o.ors_filter = (Filter *) slap_filter_objectClass_pres;
810
811                 o.ors_scope = LDAP_SCOPE_BASE;
812                 o.ors_deref = LDAP_DEREF_NEVER;
813                 an[0].an_name = op->orc_ava->aa_desc->ad_cname;
814                 an[0].an_desc = op->orc_ava->aa_desc;
815                 BER_BVZERO( &an[1].an_name );
816                 o.ors_attrs = an;
817                 o.ors_attrsonly = 0;
818
819                 o.o_acl_priv = ACL_COMPARE;
820
821                 rc = o.o_bd->be_search( &o, &r );
822
823                 if ( o.o_dn.bv_val != op->o_dn.bv_val ) {
824                         slap_op_groups_free( &o );
825                 }
826
827                 if ( rc != 0 ) {
828                         goto release;
829                 }
830
831                 if ( dlc.dlc_e != NULL ) {
832                         r.sr_entry = dlc.dlc_e;
833                 }
834
835                 if ( r.sr_err != LDAP_SUCCESS || r.sr_entry == NULL ) {
836                         /* error? */
837                         goto release;
838                 }
839
840                 for ( a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
841                         a != NULL;
842                         a = attrs_find( a->a_next, op->orc_ava->aa_desc ) )
843                 {
844                         /* if we're here, we got a match... */
845                         rs->sr_err = LDAP_COMPARE_FALSE;
846
847                         if ( attr_valfind( a,
848                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
849                                         SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
850                                 &op->orc_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 )
851                         {
852                                 rs->sr_err = LDAP_COMPARE_TRUE;
853                                 break;
854                         }
855                 }
856
857                 if ( r.sr_flags & REP_ENTRY_MUSTBEFREED ) {
858                         entry_free( r.sr_entry );
859                         r.sr_entry = NULL;
860                         r.sr_flags ^= REP_ENTRY_MUSTBEFREED;
861                 }
862         }
863
864 release:;
865         if ( e != NULL ) {
866                 overlay_entry_release_ov( op, e, 0, on );
867         }
868
869         return SLAP_CB_CONTINUE;
870 }
871
872 static int
873 dynlist_response( Operation *op, SlapReply *rs )
874 {
875         dynlist_info_t  *dli;
876
877         switch ( op->o_tag ) {
878         case LDAP_REQ_SEARCH:
879                 if ( rs->sr_type == REP_SEARCH && !get_manageDSAit( op ) )
880                 {
881                         int     rc = LDAP_OTHER;
882
883                         for ( dli = dynlist_is_dynlist_next( op, rs, NULL );
884                                 dli;
885                                 dli = dynlist_is_dynlist_next( op, rs, dli ) )
886                         {
887                                 rc = dynlist_prepare_entry( op, rs, dli );
888                         }
889
890                         if ( rc != LDAP_OTHER ) {
891                                 return rc;
892                         }
893                 }
894                 break;
895
896         case LDAP_REQ_COMPARE:
897                 switch ( rs->sr_err ) {
898                 /* NOTE: we waste a few cycles running the dynamic list
899                  * also when the result is FALSE, which occurs if the
900                  * dynamic entry itself contains the AVA attribute  */
901                 /* FIXME: this approach is less than optimal; a dedicated
902                  * compare op should be implemented, that fetches the
903                  * entry, checks if it has the appropriate objectClass
904                  * and, in case, runs a compare thru all the URIs,
905                  * stopping at the first positive occurrence; see ITS#3756 */
906                 case LDAP_COMPARE_FALSE:
907                 case LDAP_NO_SUCH_ATTRIBUTE:
908                         return dynlist_compare( op, rs );
909                 }
910                 break;
911
912         default:
913                 break;
914         }
915
916         return SLAP_CB_CONTINUE;
917 }
918
919 static int
920 dynlist_build_def_filter( dynlist_info_t *dli )
921 {
922         char    *ptr;
923
924         dli->dli_default_filter.bv_len = STRLENOF( "(!(objectClass=" "))" )
925                 + dli->dli_oc->soc_cname.bv_len;
926         dli->dli_default_filter.bv_val = ch_malloc( dli->dli_default_filter.bv_len + 1 );
927         if ( dli->dli_default_filter.bv_val == NULL ) {
928                 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: malloc failed.\n",
929                         0, 0, 0 );
930                 return -1;
931         }
932
933         ptr = lutil_strcopy( dli->dli_default_filter.bv_val, "(!(objectClass=" );
934         ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
935         ptr = lutil_strcopy( ptr, "))" );
936
937         assert( ptr == &dli->dli_default_filter.bv_val[dli->dli_default_filter.bv_len] );
938
939         return 0;
940 }
941
942 #ifdef OL_2_2_COMPAT
943 static int
944 dynlist_db_config(
945         BackendDB       *be,
946         const char      *fname,
947         int             lineno,
948         int             argc,
949         char            **argv )
950 {
951         slap_overinst   *on = (slap_overinst *)be->bd_info;
952
953         int             rc = 0;
954
955         if ( strcasecmp( argv[0], "dynlist-attrset" ) == 0 ) {
956                 dynlist_info_t          **dlip;
957                 ObjectClass             *oc;
958                 AttributeDescription    *ad = NULL,
959                                         *member_ad = NULL;
960                 dynlist_map_t           *dlm = NULL;
961                 const char              *text;
962
963                 if ( argc < 3 ) {
964                         Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
965                                 "invalid arg number #%d.\n",
966                                 fname, lineno, argc );
967                         return 1;
968                 }
969
970                 oc = oc_find( argv[1] );
971                 if ( oc == NULL ) {
972                         Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
973                                 "unable to find ObjectClass \"%s\"\n",
974                                 fname, lineno, argv[ 1 ] );
975                         return 1;
976                 }
977
978                 rc = slap_str2ad( argv[2], &ad, &text );
979                 if ( rc != LDAP_SUCCESS ) {
980                         Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
981                                 "unable to find AttributeDescription \"%s\"\n",
982                                 fname, lineno, argv[2] );
983                         return 1;
984                 }
985
986                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
987                         Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
988                                 "AttributeDescription \"%s\" "
989                                 "must be a subtype of \"labeledURI\"\n",
990                                 fname, lineno, argv[2] );
991                         return 1;
992                 }
993
994                 for ( i = 3; i < argc; i++ ) {
995                         char *arg; 
996                         char *cp;
997                         AttributeDescription *member_ad = NULL;
998                         AttributeDescription *mapped_ad = NULL;
999                         dynlist_map_t *dlmp;
1000                         dynlist_map_t *dlml;
1001
1002
1003                         /*
1004                          * If no mapped attribute is given, dn is used 
1005                          * for backward compatibility.
1006                          */
1007                         arg = argv[i];
1008                         if ( cp = strchr( arg, (int)':' ) != NULL ) {
1009                                 struct berval bv;
1010                                 ber_str2bv( arg, cp - arg, 0, &bv );
1011                                 rc = slap_bv2ad( &bv, &mapped_ad, &text );
1012                                 if ( rc != LDAP_SUCCESS ) {
1013                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1014                                                 DYNLIST_USAGE
1015                                                 "unable to find mapped AttributeDescription \"%s\"\n",
1016                                                 fname, lineno, arg );
1017                                         return 1;
1018                                 }
1019                                 
1020                                 arg = cp + 1;
1021                         }
1022
1023                         rc = slap_str2ad( arg, &member_ad, &text );
1024                         if ( rc != LDAP_SUCCESS ) {
1025                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1026                                         DYNLIST_USAGE
1027                                         "unable to find AttributeDescription \"%s\"\n",
1028                                         fname, lineno, arg );
1029                                 return 1;
1030                         }
1031
1032                         dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1033                         if ( dlm == NULL ) {
1034                                 dlm = dlmp;
1035                                 dlml = NULL;
1036                         }
1037                         dlmp->dlm_member_ad = member_ad;
1038                         dlmp->dlm_mapped_ad = mapped_ad;
1039                         dlmp->dlm_next = NULL;
1040                 
1041                         if ( dlml != NULL )
1042                                 dlml->dlm_next = dlmp;
1043                         dlml = dlmp;
1044                 }
1045
1046                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1047                         *dlip; dlip = &(*dlip)->dli_next )
1048                 {
1049                         /* 
1050                          * The same URL attribute / member attribute pair
1051                          * cannot be repeated, but we enforce this only 
1052                          * when the member attribute is unique. Performing
1053                          * the check for multiple values would require
1054                          * sorting and comparing the lists, which is left
1055                          * as a future improvement
1056                          */
1057                         if ( (*dlip)->dli_ad == ad &&
1058                              (*dlip)->dli_dlm->dlm_next == NULL &&
1059                              dlm->dlm_next == NULL &&
1060                              dlm->dlm_member_ad == (*dlip)->dli_dlm->dlm_member_ad &&
1061                              dlm->dlm_mapped_ad == (*dlip)->dli_dlm->dlm_mapped_ad ) {
1062                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1063                                         DYNLIST_USAGE
1064                                         "URL attributeDescription \"%s\" already mapped.\n",
1065                                         fname, lineno, ad->ad_cname.bv_val );
1066 #if 0
1067                                 /* make it a warning... */
1068                                 return 1;
1069 #endif
1070                         }
1071                 }
1072
1073                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1074                 (*dlip)->dli_oc = oc;
1075                 (*dlip)->dli_ad = ad;
1076                 (*dlip)->dli_dlm = dlm;
1077
1078                 if ( dynlist_build_def_filter( *dlip ) ) {
1079                         dynlist_map_t *dlm = (*dlip)->ldi_dlm;
1080                         dynlist_map_t *dlm_next;
1081
1082                         while ( dlm != NULL ) {
1083                                 dlm_next = dlm->dlm_next;
1084                                 ch_free( dlm );
1085                                 dlm = dlm_next;
1086                         }
1087
1088                         ch_free( *dlip );
1089                         *dlip = NULL;
1090                         return 1;
1091                 }
1092
1093         /* allow dyngroup syntax */
1094         } else if ( strcasecmp( argv[0], "dynlist-attrpair" ) == 0 ) {
1095                 dynlist_info_t          **dlip;
1096                 ObjectClass             *oc;
1097                 AttributeDescription    *ad = NULL,
1098                                         *member_ad = NULL;
1099                 const char              *text;
1100
1101                 if ( argc != 3 ) {
1102                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1103                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1104                                 "invalid arg number #%d.\n",
1105                                 fname, lineno, argc );
1106                         return 1;
1107                 }
1108
1109                 oc = oc_find( "groupOfURLs" );
1110                 if ( oc == NULL ) {
1111                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1112                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1113                                 "unable to find default ObjectClass \"groupOfURLs\"\n",
1114                                 fname, lineno, 0 );
1115                         return 1;
1116                 }
1117
1118                 rc = slap_str2ad( argv[1], &member_ad, &text );
1119                 if ( rc != LDAP_SUCCESS ) {
1120                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1121                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1122                                 "unable to find AttributeDescription \"%s\"\n",
1123                                 fname, lineno, argv[1] );
1124                         return 1;
1125                 }
1126
1127                 rc = slap_str2ad( argv[2], &ad, &text );
1128                 if ( rc != LDAP_SUCCESS ) {
1129                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1130                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1131                                 "unable to find AttributeDescription \"%s\"\n",
1132                                 fname, lineno, argv[2] );
1133                         return 1;
1134                 }
1135
1136                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1137                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1138                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1139                                 "AttributeDescription \"%s\" "
1140                                 "must be a subtype of \"labeledURI\"\n",
1141                                 fname, lineno, argv[2] );
1142                         return 1;
1143                 }
1144
1145                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1146                         *dlip; dlip = &(*dlip)->dli_next )
1147                 {
1148                         /* 
1149                          * The same URL attribute / member attribute pair
1150                          * cannot be repeated, but we enforce this only 
1151                          * when the member attribute is unique. Performing
1152                          * the check for multiple values would require
1153                          * sorting and comparing the lists, which is left
1154                          * as a future improvement
1155                          */
1156                         if ( (*dlip)->dli_ad == ad &&
1157                              (*dlip)->dli_dlm->dlm_next == NULL &&
1158                              member_ad == (*dlip)->dli_dlm->dlm_member_ad ) {
1159                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1160                                         "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1161                                         "URL attributeDescription \"%s\" already mapped.\n",
1162                                         fname, lineno, ad->ad_cname.bv_val );
1163 #if 0
1164                                 /* make it a warning... */
1165                                 return 1;
1166 #endif
1167                         }
1168                 }
1169
1170                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1171                 (*dlip)->dli_oc = oc;
1172                 (*dlip)->dli_ad = ad;
1173                 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1174                 (*dlip)->dli_dlm->dlm_member_ad = member_ad;
1175                 (*dlip)->dli_dlm->dlm_mapped_ad = NULL;
1176
1177                 if ( dynlist_build_def_filter( *dlip ) ) {
1178                         ch_free( (*dlip)->dli_dlm );
1179                         ch_free( *dlip );
1180                         *dlip = NULL;
1181                         return 1;
1182                 }
1183
1184         } else {
1185                 rc = SLAP_CONF_UNKNOWN;
1186         }
1187
1188         return rc;
1189 }
1190
1191 #else
1192 enum {
1193         DL_ATTRSET = 1,
1194         DL_ATTRPAIR,
1195         DL_ATTRPAIR_COMPAT,
1196         DL_LAST
1197 };
1198
1199 static ConfigDriver     dl_cfgen;
1200
1201 /* XXXmanu 255 is the maximum arguments we allow. Can we go beyond? */
1202 static ConfigTable dlcfg[] = {
1203         { "dynlist-attrset", "group-oc> [uri] <URL-ad> <[mapped:]member-ad> [...]",
1204                 3, 0, 0, ARG_MAGIC|DL_ATTRSET, dl_cfgen,
1205                 "( OLcfgOvAt:8.1 NAME 'olcDlAttrSet' "
1206                         "DESC 'Dynamic list: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1207                         "EQUALITY caseIgnoreMatch "
1208                         "SYNTAX OMsDirectoryString "
1209                         "X-ORDERED 'VALUES' )",
1210                         NULL, NULL },
1211         { "dynlist-attrpair", "member-ad> <URL-ad",
1212                 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR, dl_cfgen,
1213                         NULL, NULL, NULL },
1214 #ifdef TAKEOVER_DYNGROUP
1215         { "attrpair", "member-ad> <URL-ad",
1216                 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR_COMPAT, dl_cfgen,
1217                         NULL, NULL, NULL },
1218 #endif
1219         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1220 };
1221
1222 static ConfigOCs dlocs[] = {
1223         { "( OLcfgOvOc:8.1 "
1224                 "NAME 'olcDynamicList' "
1225                 "DESC 'Dynamic list configuration' "
1226                 "SUP olcOverlayConfig "
1227                 "MAY olcDLattrSet )",
1228                 Cft_Overlay, dlcfg, NULL, NULL },
1229         { NULL, 0, NULL }
1230 };
1231
1232 static int
1233 dl_cfgen( ConfigArgs *c )
1234 {
1235         slap_overinst   *on = (slap_overinst *)c->bi;
1236         dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private;
1237
1238         int             rc = 0, i;
1239
1240         if ( c->op == SLAP_CONFIG_EMIT ) {
1241                 switch( c->type ) {
1242                 case DL_ATTRSET:
1243                         for ( i = 0; dli; i++, dli = dli->dli_next ) {
1244                                 struct berval   bv;
1245                                 char            *ptr = c->cr_msg;
1246                                 dynlist_map_t   *dlm;
1247
1248                                 assert( dli->dli_oc != NULL );
1249                                 assert( dli->dli_ad != NULL );
1250
1251                                 /* FIXME: check buffer overflow! */
1252                                 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1253                                         SLAP_X_ORDERED_FMT "%s", i,
1254                                         dli->dli_oc->soc_cname.bv_val );
1255
1256                                 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1257                                         *ptr++ = ' ';
1258                                         *ptr++ = '"';
1259                                         ptr = lutil_strncopy( ptr, dli->dli_uri.bv_val,
1260                                                 dli->dli_uri.bv_len );
1261                                         *ptr++ = '"';
1262                                 }
1263
1264                                 *ptr++ = ' ';
1265                                 ptr = lutil_strncopy( ptr, dli->dli_oc->soc_cname.bv_val,
1266                                         dli->dli_oc->soc_cname.bv_len );
1267
1268                                 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
1269                                         ptr[ 0 ] = ' ';
1270                                         ptr++;
1271                                         if ( dlm->dlm_mapped_ad ) {
1272                                                 ptr = lutil_strcopy( ptr, dlm->dlm_mapped_ad->ad_cname.bv_val );
1273                                                 ptr[ 0 ] = ':';
1274                                                 ptr++;
1275                                         }
1276                                                 
1277                                         ptr = lutil_strcopy( ptr, dlm->dlm_member_ad->ad_cname.bv_val );
1278                                 }
1279
1280                                 bv.bv_val = c->cr_msg;
1281                                 bv.bv_len = ptr - bv.bv_val;
1282                                 value_add_one( &c->rvalue_vals, &bv );
1283                         }
1284                         break;
1285
1286                 case DL_ATTRPAIR_COMPAT:
1287                 case DL_ATTRPAIR:
1288                         rc = 1;
1289                         break;
1290
1291                 default:
1292                         rc = 1;
1293                         break;
1294                 }
1295
1296                 return rc;
1297
1298         } else if ( c->op == LDAP_MOD_DELETE ) {
1299                 switch( c->type ) {
1300                 case DL_ATTRSET:
1301                         if ( c->valx < 0 ) {
1302                                 dynlist_info_t  *dli_next;
1303
1304                                 for ( dli_next = dli; dli_next; dli = dli_next ) {
1305                                         dynlist_map_t *dlm = dli->dli_dlm;
1306                                         dynlist_map_t *dlm_next;
1307
1308                                         dli_next = dli->dli_next;
1309
1310                                         if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1311                                                 ch_free( dli->dli_uri.bv_val );
1312                                         }
1313
1314                                         if ( dli->dli_lud != NULL ) {
1315                                                 ldap_free_urldesc( dli->dli_lud );
1316                                         }
1317
1318                                         if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1319                                                 ber_memfree( dli->dli_uri_nbase.bv_val );
1320                                         }
1321
1322                                         if ( dli->dli_uri_filter != NULL ) {
1323                                                 filter_free( dli->dli_uri_filter );
1324                                         }
1325
1326                                         ch_free( dli->dli_default_filter.bv_val );
1327
1328                                         while ( dlm != NULL ) {
1329                                                 dlm_next = dlm->dlm_next;
1330                                                 ch_free( dlm );
1331                                                 dlm = dlm_next;
1332                                         }
1333                                         ch_free( dli );
1334                                 }
1335
1336                                 on->on_bi.bi_private = NULL;
1337
1338                         } else {
1339                                 dynlist_info_t  **dlip;
1340                                 dynlist_map_t *dlm;
1341                                 dynlist_map_t *dlm_next;
1342
1343                                 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1344                                         i < c->valx; i++ )
1345                                 {
1346                                         if ( *dlip == NULL ) {
1347                                                 return 1;
1348                                         }
1349                                         dlip = &(*dlip)->dli_next;
1350                                 }
1351
1352                                 dli = *dlip;
1353                                 *dlip = dli->dli_next;
1354
1355                                 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1356                                         ch_free( dli->dli_uri.bv_val );
1357                                 }
1358
1359                                 if ( dli->dli_lud != NULL ) {
1360                                         ldap_free_urldesc( dli->dli_lud );
1361                                 }
1362
1363                                 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1364                                         ber_memfree( dli->dli_uri_nbase.bv_val );
1365                                 }
1366
1367                                 if ( dli->dli_uri_filter != NULL ) {
1368                                         filter_free( dli->dli_uri_filter );
1369                                 }
1370
1371                                 ch_free( dli->dli_default_filter.bv_val );
1372
1373                                 dlm = dli->dli_dlm;
1374                                 while ( dlm != NULL ) {
1375                                         dlm_next = dlm->dlm_next;
1376                                         ch_free( dlm );
1377                                         dlm = dlm_next;
1378                                 }
1379                                 ch_free( dli );
1380
1381                                 dli = (dynlist_info_t *)on->on_bi.bi_private;
1382                         }
1383                         break;
1384
1385                 case DL_ATTRPAIR_COMPAT:
1386                 case DL_ATTRPAIR:
1387                         rc = 1;
1388                         break;
1389
1390                 default:
1391                         rc = 1;
1392                         break;
1393                 }
1394
1395                 return rc;
1396         }
1397
1398         switch( c->type ) {
1399         case DL_ATTRSET: {
1400                 dynlist_info_t          **dlip,
1401                                         *dli_next = NULL;
1402                 ObjectClass             *oc = NULL;
1403                 AttributeDescription    *ad = NULL;
1404                 int                     attridx = 2;
1405                 LDAPURLDesc             *lud = NULL;
1406                 struct berval           nbase = BER_BVNULL;
1407                 Filter                  *filter = NULL;
1408                 struct berval           uri = BER_BVNULL;
1409                 dynlist_map_t           *dlm = NULL;
1410                 const char              *text;
1411
1412                 oc = oc_find( c->argv[ 1 ] );
1413                 if ( oc == NULL ) {
1414                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1415                                 "unable to find ObjectClass \"%s\"",
1416                                 c->argv[ 1 ] );
1417                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1418                                 c->log, c->cr_msg, 0 );
1419                         return 1;
1420                 }
1421
1422                 if ( strncasecmp( c->argv[ attridx ], "ldap://", STRLENOF("ldap://") ) == 0 ) {
1423                         if ( ldap_url_parse( c->argv[ attridx ], &lud ) != LDAP_URL_SUCCESS ) {
1424                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1425                                         "unable to parse URI \"%s\"",
1426                                         c->argv[ attridx ] );
1427                                 rc = 1;
1428                                 goto done_uri;
1429                         }
1430
1431                         if ( lud->lud_host != NULL ) {
1432                                 if ( lud->lud_host[0] == '\0' ) {
1433                                         ch_free( lud->lud_host );
1434                                         lud->lud_host = NULL;
1435
1436                                 } else {
1437                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1438                                                 "host not allowed in URI \"%s\"",
1439                                                 c->argv[ attridx ] );
1440                                         rc = 1;
1441                                         goto done_uri;
1442                                 }
1443                         }
1444
1445                         if ( lud->lud_attrs != NULL ) {
1446                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1447                                         "attrs not allowed in URI \"%s\"",
1448                                         c->argv[ attridx ] );
1449                                 rc = 1;
1450                                 goto done_uri;
1451                         }
1452
1453                         if ( lud->lud_exts != NULL ) {
1454                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1455                                         "extensions not allowed in URI \"%s\"",
1456                                         c->argv[ attridx ] );
1457                                 rc = 1;
1458                                 goto done_uri;
1459                         }
1460
1461                         if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' ) {
1462                                 struct berval dn;
1463                                 ber_str2bv( lud->lud_dn, 0, 0, &dn );
1464                                 rc = dnNormalize( 0, NULL, NULL, &dn, &nbase, NULL );
1465                                 if ( rc != LDAP_SUCCESS ) {
1466                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1467                                                 "DN normalization failed in URI \"%s\"",
1468                                                 c->argv[ attridx ] );
1469                                         goto done_uri;
1470                                 }
1471                         }
1472
1473                         if ( lud->lud_filter != NULL && lud->lud_filter[ 0 ] != '\0' ) {
1474                                 filter = str2filter( lud->lud_filter );
1475                                 if ( filter == NULL ) {
1476                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1477                                                 "filter parsing failed in URI \"%s\"",
1478                                                 c->argv[ attridx ] );
1479                                         rc = 1;
1480                                         goto done_uri;
1481                                 }
1482                         }
1483
1484                         ber_str2bv( c->argv[ attridx ], 0, 1, &uri );
1485
1486 done_uri:;
1487                         if ( rc ) {
1488                                 if ( lud ) {
1489                                         ldap_free_urldesc( lud );
1490                                 }
1491
1492                                 if ( !BER_BVISNULL( &nbase ) ) {
1493                                         ber_memfree( nbase.bv_val );
1494                                 }
1495
1496                                 if ( filter != NULL ) {
1497                                         filter_free( filter );
1498                                 }
1499
1500                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1501                                         c->log, c->cr_msg, 0 );
1502
1503                                 return rc;
1504                         }
1505
1506                         attridx++;
1507                 }
1508
1509                 rc = slap_str2ad( c->argv[ attridx ], &ad, &text );
1510                 if ( rc != LDAP_SUCCESS ) {
1511                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1512                                 "unable to find AttributeDescription \"%s\"",
1513                                 c->argv[ attridx ] );
1514                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1515                                 c->log, c->cr_msg, 0 );
1516                         return 1;
1517                 }
1518
1519                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1520                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1521                                 "AttributeDescription \"%s\" "
1522                                 "must be a subtype of \"labeledURI\"",
1523                                 c->argv[ attridx ] );
1524                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1525                                 c->log, c->cr_msg, 0 );
1526                         return 1;
1527                 }
1528
1529                 attridx++;
1530
1531                 for ( i = attridx; i < c->argc; i++ ) {
1532                         char *arg; 
1533                         char *cp;
1534                         AttributeDescription *member_ad = NULL;
1535                         AttributeDescription *mapped_ad = NULL;
1536                         dynlist_map_t *dlmp;
1537                         dynlist_map_t *dlml;
1538
1539
1540                         /*
1541                          * If no mapped attribute is given, dn is used 
1542                          * for backward compatibility.
1543                          */
1544                         arg = c->argv[i];
1545                         if ( ( cp = strchr( arg, ':' ) ) != NULL ) {
1546                                 struct berval bv;
1547                                 ber_str2bv( arg, cp - arg, 0, &bv );
1548                                 rc = slap_bv2ad( &bv, &mapped_ad, &text );
1549                                 if ( rc != LDAP_SUCCESS ) {
1550                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1551                                                 DYNLIST_USAGE
1552                                                 "unable to find mapped AttributeDescription #%d \"%s\"\n",
1553                                                 i - 3, c->argv[ i ] );
1554                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1555                                                 c->log, c->cr_msg, 0 );
1556                                         return 1;
1557                                 }
1558                                 arg = cp + 1;
1559                         }
1560
1561                         rc = slap_str2ad( arg, &member_ad, &text );
1562                         if ( rc != LDAP_SUCCESS ) {
1563                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1564                                         DYNLIST_USAGE
1565                                         "unable to find AttributeDescription #%d \"%s\"\n",
1566                                         i - 3, c->argv[ i ] );
1567                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1568                                         c->log, c->cr_msg, 0 );
1569                                 return 1;
1570                         }
1571
1572                         dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1573                         if ( dlm == NULL ) {
1574                                 dlm = dlmp;
1575                                 dlml = NULL;
1576                         }
1577                         dlmp->dlm_member_ad = member_ad;
1578                         dlmp->dlm_mapped_ad = mapped_ad;
1579                         dlmp->dlm_next = NULL;
1580                 
1581                         if ( dlml != NULL ) 
1582                                 dlml->dlm_next = dlmp;
1583                         dlml = dlmp;
1584                 }
1585
1586                 if ( c->valx > 0 ) {
1587                         int     i;
1588
1589                         for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1590                                 i < c->valx; i++ )
1591                         {
1592                                 if ( *dlip == NULL ) {
1593                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1594                                                 DYNLIST_USAGE
1595                                                 "invalid index {%d}\n",
1596                                                 c->valx );
1597                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1598                                                 c->log, c->cr_msg, 0 );
1599                                         return 1;
1600                                 }
1601                                 dlip = &(*dlip)->dli_next;
1602                         }
1603                         dli_next = *dlip;
1604
1605                 } else {
1606                         for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1607                                 *dlip; dlip = &(*dlip)->dli_next )
1608                                 /* goto last */;
1609                 }
1610
1611                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1612
1613                 (*dlip)->dli_oc = oc;
1614                 (*dlip)->dli_ad = ad;
1615                 (*dlip)->dli_dlm = dlm;
1616                 (*dlip)->dli_next = dli_next;
1617
1618                 (*dlip)->dli_lud = lud;
1619                 (*dlip)->dli_uri_nbase = nbase;
1620                 (*dlip)->dli_uri_filter = filter;
1621                 (*dlip)->dli_uri = uri;
1622
1623                 rc = dynlist_build_def_filter( *dlip );
1624
1625                 } break;
1626
1627         case DL_ATTRPAIR_COMPAT:
1628                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1629                         "warning: \"attrpair\" only supported for limited "
1630                         "backward compatibility with overlay \"dyngroup\"" );
1631                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1632                 /* fallthru */
1633
1634         case DL_ATTRPAIR: {
1635                 dynlist_info_t          **dlip;
1636                 ObjectClass             *oc = NULL;
1637                 AttributeDescription    *ad = NULL,
1638                                         *member_ad = NULL;
1639                 const char              *text;
1640
1641                 oc = oc_find( "groupOfURLs" );
1642                 if ( oc == NULL ) {
1643                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1644                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1645                                 "unable to find default ObjectClass \"groupOfURLs\"" );
1646                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1647                                 c->log, c->cr_msg, 0 );
1648                         return 1;
1649                 }
1650
1651                 rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text );
1652                 if ( rc != LDAP_SUCCESS ) {
1653                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1654                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1655                                 "unable to find AttributeDescription \"%s\"",
1656                                 c->argv[ 1 ] );
1657                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1658                                 c->log, c->cr_msg, 0 );
1659                         return 1;
1660                 }
1661
1662                 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
1663                 if ( rc != LDAP_SUCCESS ) {
1664                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1665                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1666                                 "unable to find AttributeDescription \"%s\"\n",
1667                                 c->argv[ 2 ] );
1668                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1669                                 c->log, c->cr_msg, 0 );
1670                         return 1;
1671                 }
1672
1673                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1674                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1675                                 DYNLIST_USAGE
1676                                 "AttributeDescription \"%s\" "
1677                                 "must be a subtype of \"labeledURI\"",
1678                                 c->argv[ 2 ] );
1679                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1680                                 c->log, c->cr_msg, 0 );
1681                         return 1;
1682                 }
1683
1684                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1685                         *dlip; dlip = &(*dlip)->dli_next )
1686                 {
1687                         /* 
1688                          * The same URL attribute / member attribute pair
1689                          * cannot be repeated, but we enforce this only 
1690                          * when the member attribute is unique. Performing
1691                          * the check for multiple values would require
1692                          * sorting and comparing the lists, which is left
1693                          * as a future improvement
1694                          */
1695                         if ( (*dlip)->dli_ad == ad &&
1696                              (*dlip)->dli_dlm->dlm_next == NULL &&
1697                              member_ad == (*dlip)->dli_dlm->dlm_member_ad ) {
1698                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1699                                         "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1700                                         "URL attributeDescription \"%s\" already mapped.\n",
1701                                         ad->ad_cname.bv_val );
1702                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1703                                         c->log, c->cr_msg, 0 );
1704 #if 0
1705                                 /* make it a warning... */
1706                                 return 1;
1707 #endif
1708                         }
1709                 }
1710
1711                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1712
1713                 (*dlip)->dli_oc = oc;
1714                 (*dlip)->dli_ad = ad;
1715                 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1716                 (*dlip)->dli_dlm->dlm_member_ad = member_ad;
1717                 (*dlip)->dli_dlm->dlm_mapped_ad = NULL;
1718
1719                 rc = dynlist_build_def_filter( *dlip );
1720
1721                 } break;
1722
1723         default:
1724                 rc = 1;
1725                 break;
1726         }
1727
1728         return rc;
1729 }
1730 #endif
1731
1732 static int
1733 dynlist_db_open(
1734         BackendDB       *be,
1735         ConfigReply     *cr )
1736 {
1737         slap_overinst           *on = (slap_overinst *) be->bd_info;
1738         dynlist_info_t          *dli = (dynlist_info_t *)on->on_bi.bi_private;
1739         ObjectClass             *oc = NULL;
1740         AttributeDescription    *ad = NULL;
1741         const char      *text;
1742         int rc;
1743
1744         if ( dli == NULL ) {
1745                 dli = ch_calloc( 1, sizeof( dynlist_info_t ) );
1746                 on->on_bi.bi_private = (void *)dli;
1747         }
1748
1749         for ( ; dli; dli = dli->dli_next ) {
1750                 if ( dli->dli_oc == NULL ) {
1751                         if ( oc == NULL ) {
1752                                 oc = oc_find( "groupOfURLs" );
1753                                 if ( oc == NULL ) {
1754                                         snprintf( cr->msg, sizeof( cr->msg),
1755                                                 "unable to fetch objectClass \"groupOfURLs\"" );
1756                                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1757                                         return 1;
1758                                 }
1759                         }
1760
1761                         dli->dli_oc = oc;
1762                 }
1763
1764                 if ( dli->dli_ad == NULL ) {
1765                         if ( ad == NULL ) {
1766                                 rc = slap_str2ad( "memberURL", &ad, &text );
1767                                 if ( rc != LDAP_SUCCESS ) {
1768                                         snprintf( cr->msg, sizeof( cr->msg),
1769                                                 "unable to fetch attributeDescription \"memberURL\": %d (%s)",
1770                                                 rc, text );
1771                                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1772                                         return 1;
1773                                 }
1774                         }
1775                 
1776                         dli->dli_ad = ad;                       
1777                 }
1778
1779                 if ( BER_BVISNULL( &dli->dli_default_filter ) ) {
1780                         rc = dynlist_build_def_filter( dli );
1781                         if ( rc != 0 ) {
1782                                 return rc;
1783                         }
1784                 }
1785         }
1786
1787         if ( ad_dgIdentity == NULL ) {
1788                 rc = slap_str2ad( "dgIdentity", &ad_dgIdentity, &text );
1789                 if ( rc != LDAP_SUCCESS ) {
1790                         snprintf( cr->msg, sizeof( cr->msg),
1791                                 "unable to fetch attributeDescription \"dgIdentity\": %d (%s)",
1792                                 rc, text );
1793                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 );
1794                         /* Just a warning */
1795                 }
1796         }
1797
1798         if ( ad_dgAuthz == NULL ) {
1799                 rc = slap_str2ad( "dgAuthz", &ad_dgAuthz, &text );
1800                 if ( rc != LDAP_SUCCESS ) {
1801                         snprintf( cr->msg, sizeof( cr->msg),
1802                                 "unable to fetch attributeDescription \"dgAuthz\": %d (%s)",
1803                                 rc, text );
1804                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 );
1805                         /* Just a warning */
1806                 }
1807         }
1808
1809         return 0;
1810 }
1811
1812 static int
1813 dynlist_db_destroy(
1814         BackendDB       *be,
1815         ConfigReply     *cr )
1816 {
1817         slap_overinst   *on = (slap_overinst *) be->bd_info;
1818
1819         if ( on->on_bi.bi_private ) {
1820                 dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private,
1821                                 *dli_next;
1822
1823                 for ( dli_next = dli; dli_next; dli = dli_next ) {
1824                         dynlist_map_t *dlm;
1825                         dynlist_map_t *dlm_next;
1826
1827                         dli_next = dli->dli_next;
1828
1829                         if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1830                                 ch_free( dli->dli_uri.bv_val );
1831                         }
1832
1833                         if ( dli->dli_lud != NULL ) {
1834                                 ldap_free_urldesc( dli->dli_lud );
1835                         }
1836
1837                         if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1838                                 ber_memfree( dli->dli_uri_nbase.bv_val );
1839                         }
1840
1841                         if ( dli->dli_uri_filter != NULL ) {
1842                                 filter_free( dli->dli_uri_filter );
1843                         }
1844
1845                         ch_free( dli->dli_default_filter.bv_val );
1846
1847                         dlm = dli->dli_dlm;
1848                         while ( dlm != NULL ) {
1849                                 dlm_next = dlm->dlm_next;
1850                                 ch_free( dlm );
1851                                 dlm = dlm_next;
1852                         }
1853                         ch_free( dli );
1854                 }
1855         }
1856
1857         return 0;
1858 }
1859
1860 static slap_overinst    dynlist = { { NULL } };
1861 #ifdef TAKEOVER_DYNGROUP
1862 static char             *obsolete_names[] = {
1863         "dyngroup",
1864         NULL
1865 };
1866 #endif
1867
1868 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1869 static
1870 #endif /* SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC */
1871 int
1872 dynlist_initialize(void)
1873 {
1874 #ifndef OL_2_2_COMPAT
1875         int     rc = 0;
1876 #endif
1877
1878         dynlist.on_bi.bi_type = "dynlist";
1879
1880 #ifdef TAKEOVER_DYNGROUP
1881         /* makes dynlist incompatible with dyngroup */
1882         dynlist.on_bi.bi_obsolete_names = obsolete_names;
1883 #endif
1884
1885 #ifdef OL_2_2_COMPAT
1886         dynlist.on_bi.bi_db_config = dynlist_db_config;
1887 #else
1888         dynlist.on_bi.bi_db_config = config_generic_wrapper;
1889 #endif
1890         dynlist.on_bi.bi_db_open = dynlist_db_open;
1891         dynlist.on_bi.bi_db_destroy = dynlist_db_destroy;
1892
1893         dynlist.on_response = dynlist_response;
1894
1895 #ifndef OL_2_2_COMPAT
1896         dynlist.on_bi.bi_cf_ocs = dlocs;
1897
1898         rc = config_register_schema( dlcfg, dlocs );
1899         if ( rc ) {
1900                 return rc;
1901         }
1902 #endif
1903
1904         return overlay_register( &dynlist );
1905 }
1906
1907 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1908 int
1909 init_module( int argc, char *argv[] )
1910 {
1911         return dynlist_initialize();
1912 }
1913 #endif
1914
1915 #endif /* SLAPD_OVER_DYNLIST */