]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/dynlist.c
ITS#6308 lock leak: must release entry using same op that acquired it
[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, slap_bv_operational_attrs );
270         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, slap_bv_user_attrs );
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, slap_bv_operational_attrs );
420         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, slap_bv_user_attrs );
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( &o, 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, *dlml = 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
1001
1002                         /*
1003                          * If no mapped attribute is given, dn is used 
1004                          * for backward compatibility.
1005                          */
1006                         arg = argv[i];
1007                         if ( cp = strchr( arg, (int)':' ) != NULL ) {
1008                                 struct berval bv;
1009                                 ber_str2bv( arg, cp - arg, 0, &bv );
1010                                 rc = slap_bv2ad( &bv, &mapped_ad, &text );
1011                                 if ( rc != LDAP_SUCCESS ) {
1012                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1013                                                 DYNLIST_USAGE
1014                                                 "unable to find mapped AttributeDescription \"%s\"\n",
1015                                                 fname, lineno, arg );
1016                                         return 1;
1017                                 }
1018                                 
1019                                 arg = cp + 1;
1020                         }
1021
1022                         rc = slap_str2ad( arg, &member_ad, &text );
1023                         if ( rc != LDAP_SUCCESS ) {
1024                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1025                                         DYNLIST_USAGE
1026                                         "unable to find AttributeDescription \"%s\"\n",
1027                                         fname, lineno, arg );
1028                                 return 1;
1029                         }
1030
1031                         dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1032                         if ( dlm == NULL ) {
1033                                 dlm = dlmp;
1034                         }
1035                         dlmp->dlm_member_ad = member_ad;
1036                         dlmp->dlm_mapped_ad = mapped_ad;
1037                         dlmp->dlm_next = NULL;
1038                 
1039                         if ( dlml != NULL )
1040                                 dlml->dlm_next = dlmp;
1041                         dlml = dlmp;
1042                 }
1043
1044                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1045                         *dlip; dlip = &(*dlip)->dli_next )
1046                 {
1047                         /* 
1048                          * The same URL attribute / member attribute pair
1049                          * cannot be repeated, but we enforce this only 
1050                          * when the member attribute is unique. Performing
1051                          * the check for multiple values would require
1052                          * sorting and comparing the lists, which is left
1053                          * as a future improvement
1054                          */
1055                         if ( (*dlip)->dli_ad == ad &&
1056                              (*dlip)->dli_dlm->dlm_next == NULL &&
1057                              dlm->dlm_next == NULL &&
1058                              dlm->dlm_member_ad == (*dlip)->dli_dlm->dlm_member_ad &&
1059                              dlm->dlm_mapped_ad == (*dlip)->dli_dlm->dlm_mapped_ad ) {
1060                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1061                                         DYNLIST_USAGE
1062                                         "URL attributeDescription \"%s\" already mapped.\n",
1063                                         fname, lineno, ad->ad_cname.bv_val );
1064 #if 0
1065                                 /* make it a warning... */
1066                                 return 1;
1067 #endif
1068                         }
1069                 }
1070
1071                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1072                 (*dlip)->dli_oc = oc;
1073                 (*dlip)->dli_ad = ad;
1074                 (*dlip)->dli_dlm = dlm;
1075
1076                 if ( dynlist_build_def_filter( *dlip ) ) {
1077                         dynlist_map_t *dlm = (*dlip)->ldi_dlm;
1078                         dynlist_map_t *dlm_next;
1079
1080                         while ( dlm != NULL ) {
1081                                 dlm_next = dlm->dlm_next;
1082                                 ch_free( dlm );
1083                                 dlm = dlm_next;
1084                         }
1085
1086                         ch_free( *dlip );
1087                         *dlip = NULL;
1088                         return 1;
1089                 }
1090
1091         /* allow dyngroup syntax */
1092         } else if ( strcasecmp( argv[0], "dynlist-attrpair" ) == 0 ) {
1093                 dynlist_info_t          **dlip;
1094                 ObjectClass             *oc;
1095                 AttributeDescription    *ad = NULL,
1096                                         *member_ad = NULL;
1097                 const char              *text;
1098
1099                 if ( argc != 3 ) {
1100                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1101                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1102                                 "invalid arg number #%d.\n",
1103                                 fname, lineno, argc );
1104                         return 1;
1105                 }
1106
1107                 oc = oc_find( "groupOfURLs" );
1108                 if ( oc == NULL ) {
1109                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1110                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1111                                 "unable to find default ObjectClass \"groupOfURLs\"\n",
1112                                 fname, lineno, 0 );
1113                         return 1;
1114                 }
1115
1116                 rc = slap_str2ad( argv[1], &member_ad, &text );
1117                 if ( rc != LDAP_SUCCESS ) {
1118                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1119                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1120                                 "unable to find AttributeDescription \"%s\"\n",
1121                                 fname, lineno, argv[1] );
1122                         return 1;
1123                 }
1124
1125                 rc = slap_str2ad( argv[2], &ad, &text );
1126                 if ( rc != LDAP_SUCCESS ) {
1127                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1128                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1129                                 "unable to find AttributeDescription \"%s\"\n",
1130                                 fname, lineno, argv[2] );
1131                         return 1;
1132                 }
1133
1134                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1135                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1136                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1137                                 "AttributeDescription \"%s\" "
1138                                 "must be a subtype of \"labeledURI\"\n",
1139                                 fname, lineno, argv[2] );
1140                         return 1;
1141                 }
1142
1143                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1144                         *dlip; dlip = &(*dlip)->dli_next )
1145                 {
1146                         /* 
1147                          * The same URL attribute / member attribute pair
1148                          * cannot be repeated, but we enforce this only 
1149                          * when the member attribute is unique. Performing
1150                          * the check for multiple values would require
1151                          * sorting and comparing the lists, which is left
1152                          * as a future improvement
1153                          */
1154                         if ( (*dlip)->dli_ad == ad &&
1155                              (*dlip)->dli_dlm->dlm_next == NULL &&
1156                              member_ad == (*dlip)->dli_dlm->dlm_member_ad ) {
1157                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1158                                         "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1159                                         "URL attributeDescription \"%s\" already mapped.\n",
1160                                         fname, lineno, ad->ad_cname.bv_val );
1161 #if 0
1162                                 /* make it a warning... */
1163                                 return 1;
1164 #endif
1165                         }
1166                 }
1167
1168                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1169                 (*dlip)->dli_oc = oc;
1170                 (*dlip)->dli_ad = ad;
1171                 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1172                 (*dlip)->dli_dlm->dlm_member_ad = member_ad;
1173                 (*dlip)->dli_dlm->dlm_mapped_ad = NULL;
1174
1175                 if ( dynlist_build_def_filter( *dlip ) ) {
1176                         ch_free( (*dlip)->dli_dlm );
1177                         ch_free( *dlip );
1178                         *dlip = NULL;
1179                         return 1;
1180                 }
1181
1182         } else {
1183                 rc = SLAP_CONF_UNKNOWN;
1184         }
1185
1186         return rc;
1187 }
1188
1189 #else
1190 enum {
1191         DL_ATTRSET = 1,
1192         DL_ATTRPAIR,
1193         DL_ATTRPAIR_COMPAT,
1194         DL_LAST
1195 };
1196
1197 static ConfigDriver     dl_cfgen;
1198
1199 /* XXXmanu 255 is the maximum arguments we allow. Can we go beyond? */
1200 static ConfigTable dlcfg[] = {
1201         { "dynlist-attrset", "group-oc> [uri] <URL-ad> <[mapped:]member-ad> [...]",
1202                 3, 0, 0, ARG_MAGIC|DL_ATTRSET, dl_cfgen,
1203                 "( OLcfgOvAt:8.1 NAME 'olcDlAttrSet' "
1204                         "DESC 'Dynamic list: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1205                         "EQUALITY caseIgnoreMatch "
1206                         "SYNTAX OMsDirectoryString "
1207                         "X-ORDERED 'VALUES' )",
1208                         NULL, NULL },
1209         { "dynlist-attrpair", "member-ad> <URL-ad",
1210                 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR, dl_cfgen,
1211                         NULL, NULL, NULL },
1212 #ifdef TAKEOVER_DYNGROUP
1213         { "attrpair", "member-ad> <URL-ad",
1214                 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR_COMPAT, dl_cfgen,
1215                         NULL, NULL, NULL },
1216 #endif
1217         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1218 };
1219
1220 static ConfigOCs dlocs[] = {
1221         { "( OLcfgOvOc:8.1 "
1222                 "NAME 'olcDynamicList' "
1223                 "DESC 'Dynamic list configuration' "
1224                 "SUP olcOverlayConfig "
1225                 "MAY olcDLattrSet )",
1226                 Cft_Overlay, dlcfg, NULL, NULL },
1227         { NULL, 0, NULL }
1228 };
1229
1230 static int
1231 dl_cfgen( ConfigArgs *c )
1232 {
1233         slap_overinst   *on = (slap_overinst *)c->bi;
1234         dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private;
1235
1236         int             rc = 0, i;
1237
1238         if ( c->op == SLAP_CONFIG_EMIT ) {
1239                 switch( c->type ) {
1240                 case DL_ATTRSET:
1241                         for ( i = 0; dli; i++, dli = dli->dli_next ) {
1242                                 struct berval   bv;
1243                                 char            *ptr = c->cr_msg;
1244                                 dynlist_map_t   *dlm;
1245
1246                                 assert( dli->dli_oc != NULL );
1247                                 assert( dli->dli_ad != NULL );
1248
1249                                 /* FIXME: check buffer overflow! */
1250                                 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1251                                         SLAP_X_ORDERED_FMT "%s", i,
1252                                         dli->dli_oc->soc_cname.bv_val );
1253
1254                                 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1255                                         *ptr++ = ' ';
1256                                         *ptr++ = '"';
1257                                         ptr = lutil_strncopy( ptr, dli->dli_uri.bv_val,
1258                                                 dli->dli_uri.bv_len );
1259                                         *ptr++ = '"';
1260                                 }
1261
1262                                 *ptr++ = ' ';
1263                                 ptr = lutil_strncopy( ptr, dli->dli_ad->ad_cname.bv_val,
1264                                         dli->dli_ad->ad_cname.bv_len );
1265
1266                                 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
1267                                         ptr[ 0 ] = ' ';
1268                                         ptr++;
1269                                         if ( dlm->dlm_mapped_ad ) {
1270                                                 ptr = lutil_strcopy( ptr, dlm->dlm_mapped_ad->ad_cname.bv_val );
1271                                                 ptr[ 0 ] = ':';
1272                                                 ptr++;
1273                                         }
1274                                                 
1275                                         ptr = lutil_strcopy( ptr, dlm->dlm_member_ad->ad_cname.bv_val );
1276                                 }
1277
1278                                 bv.bv_val = c->cr_msg;
1279                                 bv.bv_len = ptr - bv.bv_val;
1280                                 value_add_one( &c->rvalue_vals, &bv );
1281                         }
1282                         break;
1283
1284                 case DL_ATTRPAIR_COMPAT:
1285                 case DL_ATTRPAIR:
1286                         rc = 1;
1287                         break;
1288
1289                 default:
1290                         rc = 1;
1291                         break;
1292                 }
1293
1294                 return rc;
1295
1296         } else if ( c->op == LDAP_MOD_DELETE ) {
1297                 switch( c->type ) {
1298                 case DL_ATTRSET:
1299                         if ( c->valx < 0 ) {
1300                                 dynlist_info_t  *dli_next;
1301
1302                                 for ( dli_next = dli; dli_next; dli = dli_next ) {
1303                                         dynlist_map_t *dlm = dli->dli_dlm;
1304                                         dynlist_map_t *dlm_next;
1305
1306                                         dli_next = dli->dli_next;
1307
1308                                         if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1309                                                 ch_free( dli->dli_uri.bv_val );
1310                                         }
1311
1312                                         if ( dli->dli_lud != NULL ) {
1313                                                 ldap_free_urldesc( dli->dli_lud );
1314                                         }
1315
1316                                         if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1317                                                 ber_memfree( dli->dli_uri_nbase.bv_val );
1318                                         }
1319
1320                                         if ( dli->dli_uri_filter != NULL ) {
1321                                                 filter_free( dli->dli_uri_filter );
1322                                         }
1323
1324                                         ch_free( dli->dli_default_filter.bv_val );
1325
1326                                         while ( dlm != NULL ) {
1327                                                 dlm_next = dlm->dlm_next;
1328                                                 ch_free( dlm );
1329                                                 dlm = dlm_next;
1330                                         }
1331                                         ch_free( dli );
1332                                 }
1333
1334                                 on->on_bi.bi_private = NULL;
1335
1336                         } else {
1337                                 dynlist_info_t  **dlip;
1338                                 dynlist_map_t *dlm;
1339                                 dynlist_map_t *dlm_next;
1340
1341                                 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1342                                         i < c->valx; i++ )
1343                                 {
1344                                         if ( *dlip == NULL ) {
1345                                                 return 1;
1346                                         }
1347                                         dlip = &(*dlip)->dli_next;
1348                                 }
1349
1350                                 dli = *dlip;
1351                                 *dlip = dli->dli_next;
1352
1353                                 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1354                                         ch_free( dli->dli_uri.bv_val );
1355                                 }
1356
1357                                 if ( dli->dli_lud != NULL ) {
1358                                         ldap_free_urldesc( dli->dli_lud );
1359                                 }
1360
1361                                 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1362                                         ber_memfree( dli->dli_uri_nbase.bv_val );
1363                                 }
1364
1365                                 if ( dli->dli_uri_filter != NULL ) {
1366                                         filter_free( dli->dli_uri_filter );
1367                                 }
1368
1369                                 ch_free( dli->dli_default_filter.bv_val );
1370
1371                                 dlm = dli->dli_dlm;
1372                                 while ( dlm != NULL ) {
1373                                         dlm_next = dlm->dlm_next;
1374                                         ch_free( dlm );
1375                                         dlm = dlm_next;
1376                                 }
1377                                 ch_free( dli );
1378
1379                                 dli = (dynlist_info_t *)on->on_bi.bi_private;
1380                         }
1381                         break;
1382
1383                 case DL_ATTRPAIR_COMPAT:
1384                 case DL_ATTRPAIR:
1385                         rc = 1;
1386                         break;
1387
1388                 default:
1389                         rc = 1;
1390                         break;
1391                 }
1392
1393                 return rc;
1394         }
1395
1396         switch( c->type ) {
1397         case DL_ATTRSET: {
1398                 dynlist_info_t          **dlip,
1399                                         *dli_next = NULL;
1400                 ObjectClass             *oc = NULL;
1401                 AttributeDescription    *ad = NULL;
1402                 int                     attridx = 2;
1403                 LDAPURLDesc             *lud = NULL;
1404                 struct berval           nbase = BER_BVNULL;
1405                 Filter                  *filter = NULL;
1406                 struct berval           uri = BER_BVNULL;
1407                 dynlist_map_t           *dlm = NULL, *dlml = NULL;
1408                 const char              *text;
1409
1410                 oc = oc_find( c->argv[ 1 ] );
1411                 if ( oc == NULL ) {
1412                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1413                                 "unable to find ObjectClass \"%s\"",
1414                                 c->argv[ 1 ] );
1415                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1416                                 c->log, c->cr_msg, 0 );
1417                         return 1;
1418                 }
1419
1420                 if ( strncasecmp( c->argv[ attridx ], "ldap://", STRLENOF("ldap://") ) == 0 ) {
1421                         if ( ldap_url_parse( c->argv[ attridx ], &lud ) != LDAP_URL_SUCCESS ) {
1422                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1423                                         "unable to parse URI \"%s\"",
1424                                         c->argv[ attridx ] );
1425                                 rc = 1;
1426                                 goto done_uri;
1427                         }
1428
1429                         if ( lud->lud_host != NULL ) {
1430                                 if ( lud->lud_host[0] == '\0' ) {
1431                                         ch_free( lud->lud_host );
1432                                         lud->lud_host = NULL;
1433
1434                                 } else {
1435                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1436                                                 "host not allowed in URI \"%s\"",
1437                                                 c->argv[ attridx ] );
1438                                         rc = 1;
1439                                         goto done_uri;
1440                                 }
1441                         }
1442
1443                         if ( lud->lud_attrs != NULL ) {
1444                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1445                                         "attrs not allowed in URI \"%s\"",
1446                                         c->argv[ attridx ] );
1447                                 rc = 1;
1448                                 goto done_uri;
1449                         }
1450
1451                         if ( lud->lud_exts != NULL ) {
1452                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1453                                         "extensions not allowed in URI \"%s\"",
1454                                         c->argv[ attridx ] );
1455                                 rc = 1;
1456                                 goto done_uri;
1457                         }
1458
1459                         if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' ) {
1460                                 struct berval dn;
1461                                 ber_str2bv( lud->lud_dn, 0, 0, &dn );
1462                                 rc = dnNormalize( 0, NULL, NULL, &dn, &nbase, NULL );
1463                                 if ( rc != LDAP_SUCCESS ) {
1464                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1465                                                 "DN normalization failed in URI \"%s\"",
1466                                                 c->argv[ attridx ] );
1467                                         goto done_uri;
1468                                 }
1469                         }
1470
1471                         if ( lud->lud_filter != NULL && lud->lud_filter[ 0 ] != '\0' ) {
1472                                 filter = str2filter( lud->lud_filter );
1473                                 if ( filter == NULL ) {
1474                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1475                                                 "filter parsing failed in URI \"%s\"",
1476                                                 c->argv[ attridx ] );
1477                                         rc = 1;
1478                                         goto done_uri;
1479                                 }
1480                         }
1481
1482                         ber_str2bv( c->argv[ attridx ], 0, 1, &uri );
1483
1484 done_uri:;
1485                         if ( rc ) {
1486                                 if ( lud ) {
1487                                         ldap_free_urldesc( lud );
1488                                 }
1489
1490                                 if ( !BER_BVISNULL( &nbase ) ) {
1491                                         ber_memfree( nbase.bv_val );
1492                                 }
1493
1494                                 if ( filter != NULL ) {
1495                                         filter_free( filter );
1496                                 }
1497
1498                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1499                                         c->log, c->cr_msg, 0 );
1500
1501                                 return rc;
1502                         }
1503
1504                         attridx++;
1505                 }
1506
1507                 rc = slap_str2ad( c->argv[ attridx ], &ad, &text );
1508                 if ( rc != LDAP_SUCCESS ) {
1509                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1510                                 "unable to find AttributeDescription \"%s\"",
1511                                 c->argv[ attridx ] );
1512                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1513                                 c->log, c->cr_msg, 0 );
1514                         return 1;
1515                 }
1516
1517                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1518                         snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1519                                 "AttributeDescription \"%s\" "
1520                                 "must be a subtype of \"labeledURI\"",
1521                                 c->argv[ attridx ] );
1522                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1523                                 c->log, c->cr_msg, 0 );
1524                         return 1;
1525                 }
1526
1527                 attridx++;
1528
1529                 for ( i = attridx; i < c->argc; i++ ) {
1530                         char *arg; 
1531                         char *cp;
1532                         AttributeDescription *member_ad = NULL;
1533                         AttributeDescription *mapped_ad = NULL;
1534                         dynlist_map_t *dlmp;
1535
1536
1537                         /*
1538                          * If no mapped attribute is given, dn is used 
1539                          * for backward compatibility.
1540                          */
1541                         arg = c->argv[i];
1542                         if ( ( cp = strchr( arg, ':' ) ) != NULL ) {
1543                                 struct berval bv;
1544                                 ber_str2bv( arg, cp - arg, 0, &bv );
1545                                 rc = slap_bv2ad( &bv, &mapped_ad, &text );
1546                                 if ( rc != LDAP_SUCCESS ) {
1547                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1548                                                 DYNLIST_USAGE
1549                                                 "unable to find mapped AttributeDescription #%d \"%s\"\n",
1550                                                 i - 3, c->argv[ i ] );
1551                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1552                                                 c->log, c->cr_msg, 0 );
1553                                         return 1;
1554                                 }
1555                                 arg = cp + 1;
1556                         }
1557
1558                         rc = slap_str2ad( arg, &member_ad, &text );
1559                         if ( rc != LDAP_SUCCESS ) {
1560                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1561                                         DYNLIST_USAGE
1562                                         "unable to find AttributeDescription #%d \"%s\"\n",
1563                                         i - 3, c->argv[ i ] );
1564                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1565                                         c->log, c->cr_msg, 0 );
1566                                 return 1;
1567                         }
1568
1569                         dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1570                         if ( dlm == NULL ) {
1571                                 dlm = dlmp;
1572                         }
1573                         dlmp->dlm_member_ad = member_ad;
1574                         dlmp->dlm_mapped_ad = mapped_ad;
1575                         dlmp->dlm_next = NULL;
1576                 
1577                         if ( dlml != NULL ) 
1578                                 dlml->dlm_next = dlmp;
1579                         dlml = dlmp;
1580                 }
1581
1582                 if ( c->valx > 0 ) {
1583                         int     i;
1584
1585                         for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1586                                 i < c->valx; i++ )
1587                         {
1588                                 if ( *dlip == NULL ) {
1589                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1590                                                 DYNLIST_USAGE
1591                                                 "invalid index {%d}\n",
1592                                                 c->valx );
1593                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1594                                                 c->log, c->cr_msg, 0 );
1595                                         return 1;
1596                                 }
1597                                 dlip = &(*dlip)->dli_next;
1598                         }
1599                         dli_next = *dlip;
1600
1601                 } else {
1602                         for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1603                                 *dlip; dlip = &(*dlip)->dli_next )
1604                                 /* goto last */;
1605                 }
1606
1607                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1608
1609                 (*dlip)->dli_oc = oc;
1610                 (*dlip)->dli_ad = ad;
1611                 (*dlip)->dli_dlm = dlm;
1612                 (*dlip)->dli_next = dli_next;
1613
1614                 (*dlip)->dli_lud = lud;
1615                 (*dlip)->dli_uri_nbase = nbase;
1616                 (*dlip)->dli_uri_filter = filter;
1617                 (*dlip)->dli_uri = uri;
1618
1619                 rc = dynlist_build_def_filter( *dlip );
1620
1621                 } break;
1622
1623         case DL_ATTRPAIR_COMPAT:
1624                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1625                         "warning: \"attrpair\" only supported for limited "
1626                         "backward compatibility with overlay \"dyngroup\"" );
1627                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1628                 /* fallthru */
1629
1630         case DL_ATTRPAIR: {
1631                 dynlist_info_t          **dlip;
1632                 ObjectClass             *oc = NULL;
1633                 AttributeDescription    *ad = NULL,
1634                                         *member_ad = NULL;
1635                 const char              *text;
1636
1637                 oc = oc_find( "groupOfURLs" );
1638                 if ( oc == NULL ) {
1639                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1640                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1641                                 "unable to find default ObjectClass \"groupOfURLs\"" );
1642                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1643                                 c->log, c->cr_msg, 0 );
1644                         return 1;
1645                 }
1646
1647                 rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text );
1648                 if ( rc != LDAP_SUCCESS ) {
1649                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1650                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1651                                 "unable to find AttributeDescription \"%s\"",
1652                                 c->argv[ 1 ] );
1653                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1654                                 c->log, c->cr_msg, 0 );
1655                         return 1;
1656                 }
1657
1658                 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
1659                 if ( rc != LDAP_SUCCESS ) {
1660                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1661                                 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1662                                 "unable to find AttributeDescription \"%s\"\n",
1663                                 c->argv[ 2 ] );
1664                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1665                                 c->log, c->cr_msg, 0 );
1666                         return 1;
1667                 }
1668
1669                 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1670                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1671                                 DYNLIST_USAGE
1672                                 "AttributeDescription \"%s\" "
1673                                 "must be a subtype of \"labeledURI\"",
1674                                 c->argv[ 2 ] );
1675                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1676                                 c->log, c->cr_msg, 0 );
1677                         return 1;
1678                 }
1679
1680                 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1681                         *dlip; dlip = &(*dlip)->dli_next )
1682                 {
1683                         /* 
1684                          * The same URL attribute / member attribute pair
1685                          * cannot be repeated, but we enforce this only 
1686                          * when the member attribute is unique. Performing
1687                          * the check for multiple values would require
1688                          * sorting and comparing the lists, which is left
1689                          * as a future improvement
1690                          */
1691                         if ( (*dlip)->dli_ad == ad &&
1692                              (*dlip)->dli_dlm->dlm_next == NULL &&
1693                              member_ad == (*dlip)->dli_dlm->dlm_member_ad ) {
1694                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1695                                         "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1696                                         "URL attributeDescription \"%s\" already mapped.\n",
1697                                         ad->ad_cname.bv_val );
1698                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1699                                         c->log, c->cr_msg, 0 );
1700 #if 0
1701                                 /* make it a warning... */
1702                                 return 1;
1703 #endif
1704                         }
1705                 }
1706
1707                 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1708
1709                 (*dlip)->dli_oc = oc;
1710                 (*dlip)->dli_ad = ad;
1711                 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1712                 (*dlip)->dli_dlm->dlm_member_ad = member_ad;
1713                 (*dlip)->dli_dlm->dlm_mapped_ad = NULL;
1714
1715                 rc = dynlist_build_def_filter( *dlip );
1716
1717                 } break;
1718
1719         default:
1720                 rc = 1;
1721                 break;
1722         }
1723
1724         return rc;
1725 }
1726 #endif
1727
1728 static int
1729 dynlist_db_open(
1730         BackendDB       *be,
1731         ConfigReply     *cr )
1732 {
1733         slap_overinst           *on = (slap_overinst *) be->bd_info;
1734         dynlist_info_t          *dli = (dynlist_info_t *)on->on_bi.bi_private;
1735         ObjectClass             *oc = NULL;
1736         AttributeDescription    *ad = NULL;
1737         const char      *text;
1738         int rc;
1739
1740         if ( dli == NULL ) {
1741                 dli = ch_calloc( 1, sizeof( dynlist_info_t ) );
1742                 on->on_bi.bi_private = (void *)dli;
1743         }
1744
1745         for ( ; dli; dli = dli->dli_next ) {
1746                 if ( dli->dli_oc == NULL ) {
1747                         if ( oc == NULL ) {
1748                                 oc = oc_find( "groupOfURLs" );
1749                                 if ( oc == NULL ) {
1750                                         snprintf( cr->msg, sizeof( cr->msg),
1751                                                 "unable to fetch objectClass \"groupOfURLs\"" );
1752                                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1753                                         return 1;
1754                                 }
1755                         }
1756
1757                         dli->dli_oc = oc;
1758                 }
1759
1760                 if ( dli->dli_ad == NULL ) {
1761                         if ( ad == NULL ) {
1762                                 rc = slap_str2ad( "memberURL", &ad, &text );
1763                                 if ( rc != LDAP_SUCCESS ) {
1764                                         snprintf( cr->msg, sizeof( cr->msg),
1765                                                 "unable to fetch attributeDescription \"memberURL\": %d (%s)",
1766                                                 rc, text );
1767                                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1768                                         return 1;
1769                                 }
1770                         }
1771                 
1772                         dli->dli_ad = ad;                       
1773                 }
1774
1775                 if ( BER_BVISNULL( &dli->dli_default_filter ) ) {
1776                         rc = dynlist_build_def_filter( dli );
1777                         if ( rc != 0 ) {
1778                                 return rc;
1779                         }
1780                 }
1781         }
1782
1783         if ( ad_dgIdentity == NULL ) {
1784                 rc = slap_str2ad( "dgIdentity", &ad_dgIdentity, &text );
1785                 if ( rc != LDAP_SUCCESS ) {
1786                         snprintf( cr->msg, sizeof( cr->msg),
1787                                 "unable to fetch attributeDescription \"dgIdentity\": %d (%s)",
1788                                 rc, text );
1789                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 );
1790                         /* Just a warning */
1791                 }
1792         }
1793
1794         if ( ad_dgAuthz == NULL ) {
1795                 rc = slap_str2ad( "dgAuthz", &ad_dgAuthz, &text );
1796                 if ( rc != LDAP_SUCCESS ) {
1797                         snprintf( cr->msg, sizeof( cr->msg),
1798                                 "unable to fetch attributeDescription \"dgAuthz\": %d (%s)",
1799                                 rc, text );
1800                         Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 );
1801                         /* Just a warning */
1802                 }
1803         }
1804
1805         return 0;
1806 }
1807
1808 static int
1809 dynlist_db_destroy(
1810         BackendDB       *be,
1811         ConfigReply     *cr )
1812 {
1813         slap_overinst   *on = (slap_overinst *) be->bd_info;
1814
1815         if ( on->on_bi.bi_private ) {
1816                 dynlist_info_t  *dli = (dynlist_info_t *)on->on_bi.bi_private,
1817                                 *dli_next;
1818
1819                 for ( dli_next = dli; dli_next; dli = dli_next ) {
1820                         dynlist_map_t *dlm;
1821                         dynlist_map_t *dlm_next;
1822
1823                         dli_next = dli->dli_next;
1824
1825                         if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1826                                 ch_free( dli->dli_uri.bv_val );
1827                         }
1828
1829                         if ( dli->dli_lud != NULL ) {
1830                                 ldap_free_urldesc( dli->dli_lud );
1831                         }
1832
1833                         if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1834                                 ber_memfree( dli->dli_uri_nbase.bv_val );
1835                         }
1836
1837                         if ( dli->dli_uri_filter != NULL ) {
1838                                 filter_free( dli->dli_uri_filter );
1839                         }
1840
1841                         ch_free( dli->dli_default_filter.bv_val );
1842
1843                         dlm = dli->dli_dlm;
1844                         while ( dlm != NULL ) {
1845                                 dlm_next = dlm->dlm_next;
1846                                 ch_free( dlm );
1847                                 dlm = dlm_next;
1848                         }
1849                         ch_free( dli );
1850                 }
1851         }
1852
1853         return 0;
1854 }
1855
1856 static slap_overinst    dynlist = { { NULL } };
1857 #ifdef TAKEOVER_DYNGROUP
1858 static char             *obsolete_names[] = {
1859         "dyngroup",
1860         NULL
1861 };
1862 #endif
1863
1864 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1865 static
1866 #endif /* SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC */
1867 int
1868 dynlist_initialize(void)
1869 {
1870 #ifndef OL_2_2_COMPAT
1871         int     rc = 0;
1872 #endif
1873
1874         dynlist.on_bi.bi_type = "dynlist";
1875
1876 #ifdef TAKEOVER_DYNGROUP
1877         /* makes dynlist incompatible with dyngroup */
1878         dynlist.on_bi.bi_obsolete_names = obsolete_names;
1879 #endif
1880
1881 #ifdef OL_2_2_COMPAT
1882         dynlist.on_bi.bi_db_config = dynlist_db_config;
1883 #else
1884         dynlist.on_bi.bi_db_config = config_generic_wrapper;
1885 #endif
1886         dynlist.on_bi.bi_db_open = dynlist_db_open;
1887         dynlist.on_bi.bi_db_destroy = dynlist_db_destroy;
1888
1889         dynlist.on_response = dynlist_response;
1890
1891 #ifndef OL_2_2_COMPAT
1892         dynlist.on_bi.bi_cf_ocs = dlocs;
1893
1894         rc = config_register_schema( dlcfg, dlocs );
1895         if ( rc ) {
1896                 return rc;
1897         }
1898 #endif
1899
1900         return overlay_register( &dynlist );
1901 }
1902
1903 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1904 int
1905 init_module( int argc, char *argv[] )
1906 {
1907         return dynlist_initialize();
1908 }
1909 #endif
1910
1911 #endif /* SLAPD_OVER_DYNLIST */