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