]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/dynlist.c
set deref
[openldap] / servers / slapd / overlays / dynlist.c
1 /* dynlist.c - dynamic list overlay */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2003-2005 The OpenLDAP Foundation.
5  * Portions Copyright 2004-2005 Pierangelo Masarati.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Pierangelo Masarati
18  * for SysNet s.n.c., for inclusion in OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #ifdef SLAPD_OVER_DYNLIST
24
25 #include <stdio.h>
26
27 #include <ac/string.h>
28
29 #include "slap.h"
30 #include "lutil.h"
31
32 /* FIXME: the code differs if SLAP_OPATTRS is defined or not;
33  * SLAP_OPATTRS is not defined in 2.2 yet, while this overlay
34  * expects HEAD code at least later than August 6, 2004. */
35
36 typedef struct dynlist_info {
37         ObjectClass             *dli_oc;
38         AttributeDescription    *dli_ad;
39         AttributeDescription    *dli_member_ad;
40         struct berval           dli_default_filter;
41 } dynlist_info;
42
43 static int
44 dynlist_is_dynlist( Operation *op, SlapReply *rs )
45 {
46         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
47         dynlist_info    *dli = (dynlist_info *)on->on_bi.bi_private;
48
49         Attribute       *a;
50
51         a = attrs_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
52         if ( a == NULL ) {
53                 /* FIXME: objectClass must be present; for non-storage
54                  * backends, like back-ldap, it needs to be added
55                  * to the requested attributes */
56                 return 0;
57         }
58
59         if ( value_find_ex( slap_schema.si_ad_objectClass, 
60                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
61                         SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
62                         a->a_nvals, &dli->dli_oc->soc_cname,
63                         op->o_tmpmemctx ) == 0 )
64         {
65                 return 1;
66         }
67
68         return 0;
69 }
70
71 static int
72 dynlist_make_filter( Operation *op, struct berval *oldf, struct berval *newf )
73 {
74         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
75         dynlist_info    *dli = (dynlist_info *)on->on_bi.bi_private;
76
77         char            *ptr;
78
79         assert( oldf );
80         assert( newf );
81         assert( !BER_BVISNULL( oldf ) );
82         assert( !BER_BVISEMPTY( oldf ) );
83
84         newf->bv_len = STRLENOF( "(&(!(objectClass=" "))" ")" )
85                 + dli->dli_oc->soc_cname.bv_len + oldf->bv_len;
86         newf->bv_val = op->o_tmpalloc( newf->bv_len + 1, op->o_tmpmemctx );
87         if ( newf->bv_val == NULL ) {
88                 return -1;
89         }
90         ptr = lutil_strcopy( newf->bv_val, "(&(!(objectClass=" );
91         ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
92         ptr = lutil_strcopy( ptr, "))" );
93         ptr = lutil_strcopy( ptr, oldf->bv_val );
94         ptr = lutil_strcopy( ptr, ")" );
95         newf->bv_len = ptr - newf->bv_val;
96
97         return 0;
98 }
99
100 typedef struct dynlist_sc_t {
101         dynlist_info    *dlc_dli;
102         Entry           *dlc_e;
103 } dynlist_sc_t;
104
105 static int
106 dynlist_sc_update( Operation *op, SlapReply *rs )
107 {
108         Entry                   *e;
109         Attribute               *a;
110         int                     opattrs,
111                                 userattrs;
112         AccessControlState      acl_state = ACL_STATE_INIT;
113
114         dynlist_sc_t            *dlc;
115
116         if ( rs->sr_type != REP_SEARCH ) {
117                 return 0;
118         }
119
120         dlc = (dynlist_sc_t *)op->o_callback->sc_private;
121         e = dlc->dlc_e;
122
123         assert( e != NULL );
124         assert( rs->sr_entry != NULL );
125
126         /* test access to entry */
127         if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
128                                 NULL, ACL_READ, NULL ) )
129         {
130                 goto done;
131         }
132
133         if ( dlc->dlc_dli->dli_member_ad ) {
134
135                 /* if access allowed, try to add values, emulating permissive
136                  * control to silently ignore duplicates */
137                 if ( access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
138                                         NULL, ACL_READ, NULL ) )
139                 {
140                         Modification    mod;
141                         const char      *text = NULL;
142                         char            textbuf[1024];
143                         struct berval   vals[ 2 ], nvals[ 2 ];
144
145                         vals[ 0 ] = rs->sr_entry->e_name;
146                         BER_BVZERO( &vals[ 1 ] );
147                         nvals[ 0 ] = rs->sr_entry->e_nname;
148                         BER_BVZERO( &nvals[ 1 ] );
149
150                         mod.sm_op = LDAP_MOD_ADD;
151                         mod.sm_desc = dlc->dlc_dli->dli_member_ad;
152                         mod.sm_type = dlc->dlc_dli->dli_member_ad->ad_cname;
153                         mod.sm_values = vals;
154                         mod.sm_nvalues = nvals;
155
156                         (void)modify_add_values( e, &mod, /* permissive */ 1,
157                                         &text, textbuf, sizeof( textbuf ) );
158                 }
159
160                 goto done;
161         }
162
163 #ifndef SLAP_OPATTRS
164         opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
165         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
166 #else /* SLAP_OPATTRS */
167         opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
168         userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
169 #endif /* SLAP_OPATTRS */
170
171         for ( a = rs->sr_entry->e_attrs; a != NULL; a = a->a_next ) {
172                 BerVarray       vals, nvals = NULL;
173                 int             i, j;
174
175                 /* if attribute is not requested, skip it */
176                 if ( rs->sr_attrs == NULL ) {
177                         if ( is_at_operational( a->a_desc->ad_type ) ) {
178                                 continue;
179                         }
180
181                 } else {
182                         if ( is_at_operational( a->a_desc->ad_type ) ) {
183                                 if ( !opattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
184                                 {
185                                         continue;
186                                 }
187
188                         } else {
189                                 if ( !userattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
190                                 {
191                                         continue;
192                                 }
193                         }
194                 }
195
196                 /* test access to attribute */
197                 if ( op->ors_attrsonly ) {
198                         if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL,
199                                                 ACL_READ, &acl_state ) )
200                         {
201                                 continue;
202                         }
203                 }
204
205                 /* single-value check: keep first only */
206                 if ( is_at_single_value( a->a_desc->ad_type ) ) {
207                         if ( attr_find( e->e_attrs, a->a_desc ) != NULL ) {
208                                 continue;
209                         }
210                 }
211
212                 /* test access to attribute */
213                 for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ )
214                         /* jst count */ ;
215
216                 vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
217                 if ( a->a_nvals != a->a_vals ) {
218                         nvals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
219                 }
220
221                 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
222                         if ( access_allowed( op, rs->sr_entry, a->a_desc,
223                                                 &a->a_nvals[i], ACL_READ, &acl_state ) )
224                         {
225                                 vals[j] = a->a_vals[i];
226                                 if ( nvals ) {
227                                         nvals[j] = a->a_nvals[i];
228                                 }
229                                 j++;
230                         }
231                 }
232
233                 /* if access allowed, try to add values, emulating permissive
234                  * control to silently ignore duplicates */
235                 if ( j != 0 ) {
236                         Modification    mod;
237                         const char      *text = NULL;
238                         char            textbuf[1024];
239
240                         BER_BVZERO( &vals[j] );
241                         if ( nvals ) {
242                                 BER_BVZERO( &nvals[j] );
243                         }
244
245                         mod.sm_op = LDAP_MOD_ADD;
246                         mod.sm_desc = a->a_desc;
247                         mod.sm_type = a->a_desc->ad_cname;
248                         mod.sm_values = vals;
249                         mod.sm_nvalues = nvals;
250
251                         (void)modify_add_values( e, &mod, /* permissive */ 1,
252                                         &text, textbuf, sizeof( textbuf ) );
253                 }
254
255                 op->o_tmpfree( vals, op->o_tmpmemctx );
256                 if ( nvals ) {
257                         op->o_tmpfree( nvals, op->o_tmpmemctx );
258                 }
259         }
260
261 done:;
262         if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
263                 entry_free( rs->sr_entry );
264         }
265
266         return 0;
267 }
268         
269 static int
270 dynlist_send_entry( Operation *op, SlapReply *rs )
271 {
272         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
273         dynlist_info    *dli = (dynlist_info *)on->on_bi.bi_private;
274
275         Attribute       *a;
276         slap_callback   cb;
277         Operation       o = *op;
278         SlapReply       r = *rs;
279         struct berval   *url;
280         Entry           *e;
281         int             e_flags;
282         int             opattrs,
283                         userattrs;
284         dynlist_sc_t    dlc = { 0 };
285
286         a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad );
287         if ( a == NULL ) {
288                 /* FIXME: error? */
289                 return SLAP_CB_CONTINUE;
290         }
291
292         e = entry_dup( rs->sr_entry );
293         e_flags = rs->sr_flags | ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
294
295         dlc.dlc_e = e;
296         dlc.dlc_dli = dli;
297         cb.sc_private = &dlc;
298         cb.sc_response = dynlist_sc_update;
299         cb.sc_cleanup = NULL;
300         cb.sc_next = NULL;
301
302         o.o_callback = &cb;
303         o.ors_deref = LDAP_DEREF_NEVER;
304         o.ors_limit = NULL;
305         o.ors_tlimit = SLAP_NO_LIMIT;
306         o.ors_slimit = SLAP_NO_LIMIT;
307
308 #ifndef SLAP_OPATTRS
309         opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
310         userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
311 #else /* SLAP_OPATTRS */
312         opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
313         userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
314 #endif /* SLAP_OPATTRS */
315
316         for ( url = a->a_nvals; !BER_BVISNULL( url ); url++ ) {
317                 LDAPURLDesc     *lud = NULL;
318                 int             i, j;
319                 struct berval   dn;
320                 int             rc;
321
322                 BER_BVZERO( &o.o_req_dn );
323                 BER_BVZERO( &o.o_req_ndn );
324                 o.ors_filter = NULL;
325                 o.ors_attrs = NULL;
326                 BER_BVZERO( &o.ors_filterstr );
327
328                 if ( ldap_url_parse( url->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
329                         /* FIXME: error? */
330                         continue;
331                 }
332
333                 if ( lud->lud_host ) {
334                         /* FIXME: host not allowed; reject as illegal? */
335                         Debug( LDAP_DEBUG_ANY, "dynlist_send_entry(\"%s\"): "
336                                 "illegal URI \"%s\"\n",
337                                 e->e_name.bv_val, url->bv_val, 0 );
338                         goto cleanup;
339                 }
340
341                 if ( lud->lud_dn == NULL ) {
342                         /* note that an empty base is not honored in terms
343                          * of defaultSearchBase, because select_backend()
344                          * is not aware of the defaultSearchBase option;
345                          * this can be useful in case of a database serving
346                          * the empty suffix */
347                         BER_BVSTR( &dn, "" );
348                 } else {
349                         ber_str2bv( lud->lud_dn, 0, 0, &dn );
350                 }
351                 rc = dnPrettyNormal( NULL, &dn, &o.o_req_dn, &o.o_req_ndn, op->o_tmpmemctx );
352                 if ( rc != LDAP_SUCCESS ) {
353                         /* FIXME: error? */
354                         goto cleanup;
355                 }
356                 o.ors_scope = lud->lud_scope;
357
358                 if ( dli->dli_member_ad != NULL ) {
359                         o.ors_attrs = slap_anlist_no_attrs;
360
361                 } else if ( lud->lud_attrs == NULL ) {
362                         o.ors_attrs = rs->sr_attrs;
363
364                 } else {
365                         for ( i = 0; lud->lud_attrs[i]; i++)
366                                 /* just count */ ;
367
368                         o.ors_attrs = op->o_tmpcalloc( i + 1, sizeof( AttributeName ), op->o_tmpmemctx );
369                         for ( i = 0, j = 0; lud->lud_attrs[i]; i++) {
370                                 const char      *text = NULL;
371         
372                                 ber_str2bv( lud->lud_attrs[i], 0, 0, &o.ors_attrs[j].an_name );
373                                 o.ors_attrs[j].an_desc = NULL;
374                                 (void)slap_bv2ad( &o.ors_attrs[j].an_name, &o.ors_attrs[j].an_desc, &text );
375                                 /* FIXME: ignore errors... */
376
377                                 if ( rs->sr_attrs == NULL ) {
378                                         if ( o.ors_attrs[j].an_desc != NULL &&
379                                                         is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
380                                         {
381                                                 continue;
382                                         }
383
384                                 } else {
385                                         if ( o.ors_attrs[j].an_desc != NULL &&
386                                                         is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
387                                         {
388                                                 if ( !opattrs && !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
389                                                 {
390                                                         continue;
391                                                 }
392
393                                         } else {
394                                                 if ( !userattrs && 
395                                                                 o.ors_attrs[j].an_desc != NULL &&
396                                                                 !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
397                                                 {
398                                                         continue;
399                                                 }
400                                         }
401                                 }
402
403                                 j++;
404                         }
405
406                         if ( j == 0 ) {
407                                 goto cleanup;
408                         }
409                 
410                         BER_BVZERO( &o.ors_attrs[j].an_name );
411                 }
412
413                 if ( lud->lud_filter == NULL ) {
414                         ber_dupbv_x( &o.ors_filterstr,
415                                         &dli->dli_default_filter, op->o_tmpmemctx );
416                 } else {
417                         struct berval   flt;
418                         ber_str2bv( lud->lud_filter, 0, 0, &flt );
419                         if ( dynlist_make_filter( op, &flt, &o.ors_filterstr ) ) {
420                                 /* error */
421                                 goto cleanup;
422                         }
423                 }
424                 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
425                 if ( o.ors_filter == NULL ) {
426                         goto cleanup;
427                 }
428                 
429                 o.o_bd = select_backend( &o.o_req_ndn, 0, 1 );
430                 if ( o.o_bd && o.o_bd->be_search ) {
431 #ifdef SLAP_OPATTRS
432                         r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
433 #endif /* SLAP_OPATTRS */
434                         (void)o.o_bd->be_search( &o, &r );
435                 }
436
437 cleanup:;
438                 if ( o.ors_filter ) {
439                         filter_free_x( &o, o.ors_filter );
440                 }
441                 if ( o.ors_attrs && o.ors_attrs != rs->sr_attrs
442                                 && o.ors_attrs != slap_anlist_no_attrs )
443                 {
444                         op->o_tmpfree( o.ors_attrs, op->o_tmpmemctx );
445                 }
446                 if ( !BER_BVISNULL( &o.o_req_dn ) ) {
447                         op->o_tmpfree( o.o_req_dn.bv_val, op->o_tmpmemctx );
448                 }
449                 if ( !BER_BVISNULL( &o.o_req_ndn ) ) {
450                         op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx );
451                 }
452                 if ( o.ors_filterstr.bv_val != lud->lud_filter ) {
453                         op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
454                         lud->lud_filter = NULL;
455                 }
456                 if ( lud ) {
457                         ldap_free_urldesc( lud );
458                 }
459         }
460
461         rs->sr_entry = e;
462         rs->sr_flags = e_flags;
463
464         return SLAP_CB_CONTINUE;
465 }
466
467 static int
468 dynlist_sc_save_entry( Operation *op, SlapReply *rs )
469 {
470         /* save the entry in the private field of the callback,
471          * so it doesn't get freed (it's temporary!) */
472         if ( rs->sr_entry != NULL ) {
473                 dynlist_sc_t    *dlc = (dynlist_sc_t *)op->o_callback->sc_private;
474                 dlc->dlc_e = rs->sr_entry;
475                 rs->sr_entry = NULL;
476         }
477
478         return 0;
479 }
480
481 static int
482 dynlist_compare( Operation *op, SlapReply *rs )
483 {
484         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
485         dynlist_info    *dli = (dynlist_info *)on->on_bi.bi_private;
486
487         Attribute       *a;
488         slap_callback   cb;
489         Operation       o = *op;
490         SlapReply       r = { REP_SEARCH };
491         AttributeName   an[2];
492         int             rc;
493         dynlist_sc_t    dlc = { 0 };
494
495         dlc.dlc_dli = dli;
496         cb.sc_private = &dlc;
497         cb.sc_response = dynlist_sc_save_entry;
498         cb.sc_cleanup = NULL;
499         cb.sc_next = NULL;
500         o.o_callback = &cb;
501
502         o.o_tag = LDAP_REQ_SEARCH;
503         o.ors_limit = NULL;
504         o.ors_tlimit = SLAP_NO_LIMIT;
505         o.ors_slimit = SLAP_NO_LIMIT;
506
507         o.o_bd = select_backend( &o.o_req_ndn, 0, 1 );
508         if ( !o.o_bd || !o.o_bd->be_search ) {
509                 return SLAP_CB_CONTINUE;
510         }
511
512         BER_BVSTR( &o.ors_filterstr, "(objectClass=*)" );
513         o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
514         if ( o.ors_filter == NULL ) {
515                 /* FIXME: error? */
516                 return SLAP_CB_CONTINUE;
517         }
518
519         o.ors_scope = LDAP_SCOPE_BASE;
520         o.ors_deref = LDAP_DEREF_NEVER;
521         an[0].an_name = op->orc_ava->aa_desc->ad_cname;
522         an[0].an_desc = op->orc_ava->aa_desc;
523         BER_BVZERO( &an[1].an_name );
524         o.ors_attrs = an;
525         o.ors_attrsonly = 0;
526
527         rc = o.o_bd->be_search( &o, &r );
528         filter_free_x( &o, o.ors_filter );
529
530         if ( rc != 0 ) {
531                 return rc;
532         }
533
534         if ( dlc.dlc_e != NULL ) {
535                 r.sr_entry = dlc.dlc_e;
536         }
537
538         if ( r.sr_err != LDAP_SUCCESS || r.sr_entry == NULL ) {
539                 /* error? */
540                 return SLAP_CB_CONTINUE;
541         }
542
543         /* if we're here, we got a match... */
544         rs->sr_err = LDAP_COMPARE_FALSE;
545         for ( a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
546                 a != NULL;
547                 a = attrs_find( a->a_next, op->orc_ava->aa_desc ) )
548         {
549                 if ( value_find_ex( op->orc_ava->aa_desc,
550                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
551                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
552                         a->a_nvals, &op->orc_ava->aa_value, op->o_tmpmemctx ) == 0 )
553                 {
554                         rs->sr_err = LDAP_COMPARE_TRUE;
555                         break;
556                 }
557         }
558
559         if ( r.sr_flags & REP_ENTRY_MUSTBEFREED ) {
560                 entry_free( r.sr_entry );
561         }
562
563         return SLAP_CB_CONTINUE;
564 }
565
566 static int
567 dynlist_response( Operation *op, SlapReply *rs )
568 {
569         switch ( op->o_tag ) {
570         case LDAP_REQ_SEARCH:
571                 if ( rs->sr_type == REP_SEARCH && !get_manageDSAit( op ) )
572                 {
573                         if ( dynlist_is_dynlist( op, rs ) ) {
574                                 return dynlist_send_entry( op, rs );
575                         }
576                 }
577                 break;
578
579         case LDAP_REQ_COMPARE:
580                 if ( rs->sr_err == LDAP_NO_SUCH_ATTRIBUTE ) {
581                         return dynlist_compare( op, rs );
582                 }
583                 break;
584
585         default:
586                 break;
587         }
588
589         return SLAP_CB_CONTINUE;
590 }
591
592 static int
593 dynlist_db_config(
594     BackendDB   *be,
595     const char  *fname,
596     int         lineno,
597     int         argc,
598     char        **argv
599 )
600 {
601         slap_overinst   *on = (slap_overinst *)be->bd_info;
602         dynlist_info    *dli = (dynlist_info *)on->on_bi.bi_private;
603
604         int             rc = 0;
605
606         if ( strcasecmp( argv[0], "dynlist-oc" ) == 0 ) {
607                 if ( argc != 2 ) {
608                         fprintf( stderr, "dynlist-oc <oc>\n" );
609                         return 1;
610                 }
611                 dli->dli_oc = oc_find( argv[1] );
612                 if ( dli->dli_oc == NULL ) {
613                         fprintf( stderr, "dynlist-oc <oc>: "
614                                         "unable to find ObjectClass "
615                                         "\"%s\"\n", argv[1] );
616                         return 1;
617                 }
618
619         } else if ( strcasecmp( argv[0], "dynlist-ad" ) == 0 ) {
620                 const char      *text;
621
622                 if ( argc != 2 ) {
623                         fprintf( stderr, "dynlist-ad <ad>\n" );
624                         return 1;
625                 }
626                 dli->dli_ad = NULL;
627                 rc = slap_str2ad( argv[1], &dli->dli_ad, &text );
628                 if ( rc != LDAP_SUCCESS ) {
629                         fprintf( stderr, "dynlist-ad <ad>: "
630                                         "unable to find AttributeDescription "
631                                         "\"%s\"\n", argv[1] );
632                         return 1;
633                 }
634
635         } else if ( strcasecmp( argv[0], "dynlist-member-ad" ) == 0 ) {
636                 const char      *text;
637
638                 if ( argc != 2 ) {
639                         fprintf( stderr, "dynlist-member-ad <ad>\n" );
640                         return 1;
641                 }
642                 dli->dli_member_ad = NULL;
643                 rc = slap_str2ad( argv[1], &dli->dli_member_ad, &text );
644                 if ( rc != LDAP_SUCCESS ) {
645                         fprintf( stderr, "dynlist-member-ad <ad>: "
646                                         "unable to find AttributeDescription "
647                                         "\"%s\"\n", argv[1] );
648                         return 1;
649                 }
650
651         } else {
652                 rc = SLAP_CONF_UNKNOWN;
653         }
654
655         return rc;
656 }
657
658 static int
659 dynlist_db_init(
660         BackendDB *be
661 )
662 {
663         slap_overinst   *on = (slap_overinst *) be->bd_info;
664         dynlist_info    *dli;
665
666         dli = (dynlist_info *)ch_malloc( sizeof( dynlist_info ) );
667         memset( dli, 0, sizeof( dynlist_info ) );
668
669         on->on_bi.bi_private = (void *)dli;
670
671         return 0;
672 }
673
674 static int
675 dynlist_db_open(
676         BackendDB *be
677 )
678 {
679         slap_overinst   *on = (slap_overinst *) be->bd_info;
680         dynlist_info    *dli = (dynlist_info *)on->on_bi.bi_private;
681         int             rc = 0;
682         ber_len_t       len;
683         char            *ptr;
684
685         if ( dli->dli_oc == NULL ) {
686                 fprintf( stderr, "dynlist_db_open(): missing \"dynlist-oc <ObjectClass>\"\n" );
687                 rc = -1;
688         }
689
690         if ( dli->dli_ad == NULL ) {
691                 fprintf( stderr, "dynlist_db_open(): missing \"dynlist-ad <AttributeDescription>\"\n" );
692                 rc = -1;
693         }
694
695         len = STRLENOF( "(!(objectClass=" "))" )
696                 + dli->dli_oc->soc_cname.bv_len;
697         dli->dli_default_filter.bv_val = SLAP_MALLOC( len + 1 );
698         if ( dli->dli_default_filter.bv_val == NULL ) {
699                 fprintf( stderr, "dynlist_db_open(): malloc failed\n" );
700                 return -1;
701         }
702         ptr = lutil_strcopy( dli->dli_default_filter.bv_val, "(!(objectClass=" );
703         ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
704         ptr = lutil_strcopy( ptr, "))" );
705         dli->dli_default_filter.bv_len = ptr - dli->dli_default_filter.bv_val;
706
707         return rc;
708 }
709
710 static int
711 dynlist_db_destroy(
712         BackendDB *be
713 )
714 {
715         slap_overinst   *on = (slap_overinst *) be->bd_info;
716         int             rc = 0;
717
718         if ( on->on_bi.bi_private ) {
719                 dynlist_info    *dli = (dynlist_info *)on->on_bi.bi_private;
720
721                 dli->dli_oc = NULL;
722                 dli->dli_ad = NULL;
723
724                 ch_free( dli );
725         }
726
727         return rc;
728 }
729
730 static slap_overinst dynlist = { { NULL } };
731
732 int
733 dynlist_init(void)
734 {
735         dynlist.on_bi.bi_type = "dynlist";
736         dynlist.on_bi.bi_db_init = dynlist_db_init;
737         dynlist.on_bi.bi_db_config = dynlist_db_config;
738         dynlist.on_bi.bi_db_open = dynlist_db_open;
739         dynlist.on_bi.bi_db_destroy = dynlist_db_destroy;
740
741         dynlist.on_response = dynlist_response;
742
743         return overlay_register( &dynlist );
744 }
745
746 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
747 int
748 init_module( int argc, char *argv[] )
749 {
750         return dynlist_init();
751 }
752 #endif
753
754 #endif /* SLAPD_OVER_DYNLIST */