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