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