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