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