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