1 /* dynlist.c - dynamic list overlay */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2003-2005 The OpenLDAP Foundation.
5 * Portions Copyright 2004-2005 Pierangelo Masarati.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
17 * This work was initially developed by Pierangelo Masarati
18 * for SysNet s.n.c., for inclusion in OpenLDAP Software.
23 #ifdef SLAPD_OVER_DYNLIST
25 #if LDAP_VENDOR_VERSION_MINOR != X && LDAP_VENDOR_VERSION_MINOR < 3
31 #include <ac/string.h>
39 /* FIXME: the code differs if SLAP_OPATTRS is defined or not;
40 * SLAP_OPATTRS is not defined in 2.2 yet, while this overlay
41 * expects HEAD code at least later than August 6, 2004. */
42 /* FIXME: slap_anlist_no_attrs was introduced in 2.3; here it
43 * is anticipated to allow using this overlay with 2.2. */
46 static AttributeName anlist_no_attrs[] = {
47 { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL },
48 { BER_BVNULL, NULL, 0, NULL }
51 static AttributeName *slap_anlist_no_attrs = anlist_no_attrs;
54 typedef struct dynlist_info_t {
56 AttributeDescription *dli_ad;
57 AttributeDescription *dli_member_ad;
58 struct berval dli_default_filter;
59 struct dynlist_info_t *dli_next;
62 static dynlist_info_t *
63 dynlist_is_dynlist( Operation *op, SlapReply *rs )
65 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
66 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
70 a = attrs_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
72 /* FIXME: objectClass must be present; for non-storage
73 * backends, like back-ldap, it needs to be added
74 * to the requested attributes */
78 for ( ; dli; dli = dli->dli_next ) {
79 if ( value_find_ex( slap_schema.si_ad_objectClass,
80 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
81 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
82 a->a_nvals, &dli->dli_oc->soc_cname,
83 op->o_tmpmemctx ) == 0 )
93 dynlist_make_filter( Operation *op, struct berval *oldf, struct berval *newf )
95 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
96 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
100 assert( oldf != NULL );
101 assert( newf != NULL );
102 assert( !BER_BVISNULL( oldf ) );
103 assert( !BER_BVISEMPTY( oldf ) );
105 newf->bv_len = STRLENOF( "(&(!(objectClass=" "))" ")" )
106 + dli->dli_oc->soc_cname.bv_len + oldf->bv_len;
107 newf->bv_val = op->o_tmpalloc( newf->bv_len + 1, op->o_tmpmemctx );
108 if ( newf->bv_val == NULL ) {
111 ptr = lutil_strcopy( newf->bv_val, "(&(!(objectClass=" );
112 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
113 ptr = lutil_strcopy( ptr, "))" );
114 ptr = lutil_strcopy( ptr, oldf->bv_val );
115 ptr = lutil_strcopy( ptr, ")" );
116 newf->bv_len = ptr - newf->bv_val;
121 typedef struct dynlist_sc_t {
122 dynlist_info_t *dlc_dli;
127 dynlist_sc_update( Operation *op, SlapReply *rs )
133 AccessControlState acl_state = ACL_STATE_INIT;
137 if ( rs->sr_type != REP_SEARCH ) {
141 dlc = (dynlist_sc_t *)op->o_callback->sc_private;
145 assert( rs->sr_entry != NULL );
147 /* test access to entry */
148 if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
149 NULL, ACL_READ, NULL ) )
154 if ( dlc->dlc_dli->dli_member_ad ) {
156 /* if access allowed, try to add values, emulating permissive
157 * control to silently ignore duplicates */
158 if ( access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
159 NULL, ACL_READ, NULL ) )
162 const char *text = NULL;
164 struct berval vals[ 2 ], nvals[ 2 ];
166 vals[ 0 ] = rs->sr_entry->e_name;
167 BER_BVZERO( &vals[ 1 ] );
168 nvals[ 0 ] = rs->sr_entry->e_nname;
169 BER_BVZERO( &nvals[ 1 ] );
171 mod.sm_op = LDAP_MOD_ADD;
172 mod.sm_desc = dlc->dlc_dli->dli_member_ad;
173 mod.sm_type = dlc->dlc_dli->dli_member_ad->ad_cname;
174 mod.sm_values = vals;
175 mod.sm_nvalues = nvals;
177 (void)modify_add_values( e, &mod, /* permissive */ 1,
178 &text, textbuf, sizeof( textbuf ) );
185 opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
186 userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
187 #else /* SLAP_OPATTRS */
188 opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
189 userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
190 #endif /* SLAP_OPATTRS */
192 for ( a = rs->sr_entry->e_attrs; a != NULL; a = a->a_next ) {
193 BerVarray vals, nvals = NULL;
196 /* if attribute is not requested, skip it */
197 if ( rs->sr_attrs == NULL ) {
198 if ( is_at_operational( a->a_desc->ad_type ) ) {
203 if ( is_at_operational( a->a_desc->ad_type ) ) {
204 if ( !opattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
210 if ( !userattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
217 /* test access to attribute */
218 if ( op->ors_attrsonly ) {
219 if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL,
220 ACL_READ, &acl_state ) )
226 /* single-value check: keep first only */
227 if ( is_at_single_value( a->a_desc->ad_type ) ) {
228 if ( attr_find( e->e_attrs, a->a_desc ) != NULL ) {
233 /* test access to attribute */
234 for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ )
237 vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
238 if ( a->a_nvals != a->a_vals ) {
239 nvals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
242 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
243 if ( access_allowed( op, rs->sr_entry, a->a_desc,
244 &a->a_nvals[i], ACL_READ, &acl_state ) )
246 vals[j] = a->a_vals[i];
248 nvals[j] = a->a_nvals[i];
254 /* if access allowed, try to add values, emulating permissive
255 * control to silently ignore duplicates */
258 const char *text = NULL;
261 BER_BVZERO( &vals[j] );
263 BER_BVZERO( &nvals[j] );
266 mod.sm_op = LDAP_MOD_ADD;
267 mod.sm_desc = a->a_desc;
268 mod.sm_type = a->a_desc->ad_cname;
269 mod.sm_values = vals;
270 mod.sm_nvalues = nvals;
272 (void)modify_add_values( e, &mod, /* permissive */ 1,
273 &text, textbuf, sizeof( textbuf ) );
276 op->o_tmpfree( vals, op->o_tmpmemctx );
278 op->o_tmpfree( nvals, op->o_tmpmemctx );
283 if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
284 entry_free( rs->sr_entry );
291 dynlist_send_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli )
296 SlapReply r = { REP_SEARCH };
302 dynlist_sc_t dlc = { 0 };
304 a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad );
307 return SLAP_CB_CONTINUE;
310 e = entry_dup( rs->sr_entry );
311 e_flags = rs->sr_flags | ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
315 cb.sc_private = &dlc;
316 cb.sc_response = dynlist_sc_update;
317 cb.sc_cleanup = NULL;
321 o.ors_deref = LDAP_DEREF_NEVER;
323 o.ors_tlimit = SLAP_NO_LIMIT;
324 o.ors_slimit = SLAP_NO_LIMIT;
327 opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, &AllOper );
328 userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, &AllUser );
329 #else /* SLAP_OPATTRS */
330 opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
331 userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
332 #endif /* SLAP_OPATTRS */
334 for ( url = a->a_nvals; !BER_BVISNULL( url ); url++ ) {
335 LDAPURLDesc *lud = NULL;
340 BER_BVZERO( &o.o_req_dn );
341 BER_BVZERO( &o.o_req_ndn );
344 BER_BVZERO( &o.ors_filterstr );
346 if ( ldap_url_parse( url->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
351 if ( lud->lud_host ) {
352 /* FIXME: host not allowed; reject as illegal? */
353 Debug( LDAP_DEBUG_ANY, "dynlist_send_entry(\"%s\"): "
354 "illegal URI \"%s\"\n",
355 e->e_name.bv_val, url->bv_val, 0 );
359 if ( lud->lud_dn == NULL ) {
360 /* note that an empty base is not honored in terms
361 * of defaultSearchBase, because select_backend()
362 * is not aware of the defaultSearchBase option;
363 * this can be useful in case of a database serving
364 * the empty suffix */
365 BER_BVSTR( &dn, "" );
367 ber_str2bv( lud->lud_dn, 0, 0, &dn );
369 rc = dnPrettyNormal( NULL, &dn, &o.o_req_dn, &o.o_req_ndn, op->o_tmpmemctx );
370 if ( rc != LDAP_SUCCESS ) {
374 o.ors_scope = lud->lud_scope;
376 if ( dli->dli_member_ad != NULL ) {
377 o.ors_attrs = slap_anlist_no_attrs;
379 } else if ( lud->lud_attrs == NULL ) {
380 o.ors_attrs = rs->sr_attrs;
383 for ( i = 0; lud->lud_attrs[i]; i++)
386 o.ors_attrs = op->o_tmpcalloc( i + 1, sizeof( AttributeName ), op->o_tmpmemctx );
387 for ( i = 0, j = 0; lud->lud_attrs[i]; i++) {
388 const char *text = NULL;
390 ber_str2bv( lud->lud_attrs[i], 0, 0, &o.ors_attrs[j].an_name );
391 o.ors_attrs[j].an_desc = NULL;
392 (void)slap_bv2ad( &o.ors_attrs[j].an_name, &o.ors_attrs[j].an_desc, &text );
393 /* FIXME: ignore errors... */
395 if ( rs->sr_attrs == NULL ) {
396 if ( o.ors_attrs[j].an_desc != NULL &&
397 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
403 if ( o.ors_attrs[j].an_desc != NULL &&
404 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
406 if ( !opattrs && !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
413 o.ors_attrs[j].an_desc != NULL &&
414 !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
428 BER_BVZERO( &o.ors_attrs[j].an_name );
431 if ( lud->lud_filter == NULL ) {
432 ber_dupbv_x( &o.ors_filterstr,
433 &dli->dli_default_filter, op->o_tmpmemctx );
436 ber_str2bv( lud->lud_filter, 0, 0, &flt );
437 if ( dynlist_make_filter( op, &flt, &o.ors_filterstr ) ) {
442 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
443 if ( o.ors_filter == NULL ) {
447 o.o_bd = select_backend( &o.o_req_ndn, 0, 1 );
448 if ( o.o_bd && o.o_bd->be_search ) {
450 r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
451 #endif /* SLAP_OPATTRS */
452 (void)o.o_bd->be_search( &o, &r );
456 if ( o.ors_filter ) {
457 filter_free_x( &o, o.ors_filter );
459 if ( o.ors_attrs && o.ors_attrs != rs->sr_attrs
460 && o.ors_attrs != slap_anlist_no_attrs )
462 op->o_tmpfree( o.ors_attrs, op->o_tmpmemctx );
464 if ( !BER_BVISNULL( &o.o_req_dn ) ) {
465 op->o_tmpfree( o.o_req_dn.bv_val, op->o_tmpmemctx );
467 if ( !BER_BVISNULL( &o.o_req_ndn ) ) {
468 op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx );
470 if ( o.ors_filterstr.bv_val != lud->lud_filter ) {
471 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
472 lud->lud_filter = NULL;
475 ldap_free_urldesc( lud );
480 rs->sr_flags = e_flags;
482 return SLAP_CB_CONTINUE;
486 dynlist_sc_save_entry( Operation *op, SlapReply *rs )
488 /* save the entry in the private field of the callback,
489 * so it doesn't get freed (it's temporary!) */
490 if ( rs->sr_entry != NULL ) {
491 dynlist_sc_t *dlc = (dynlist_sc_t *)op->o_callback->sc_private;
492 dlc->dlc_e = rs->sr_entry;
500 dynlist_compare( Operation *op, SlapReply *rs )
502 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
503 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
505 for ( ; dli != NULL; dli = dli->dli_next ) {
506 if ( op->oq_compare.rs_ava->aa_desc == dli->dli_member_ad ) {
507 /* This compare is for one of the attributes we're
508 * interested in. We'll use slapd's existing dyngroup
509 * evaluator to get the answer we want.
511 int cache = op->o_do_not_cache;
513 op->o_do_not_cache = 1;
514 rs->sr_err = backend_group( op, NULL, &op->o_req_ndn,
515 &op->oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad );
516 op->o_do_not_cache = cache;
517 switch ( rs->sr_err ) {
519 rs->sr_err = LDAP_COMPARE_TRUE;
522 case LDAP_NO_SUCH_OBJECT:
523 /* NOTE: backend_group() returns noSuchObject
524 * if op_ndn does not exist; however, since
525 * dynamic list expansion means that the
526 * member attribute is virtually present, the
527 * non-existence of the asserted value implies
528 * the assertion is FALSE rather than
530 rs->sr_err = LDAP_COMPARE_FALSE;
533 return SLAP_CB_CONTINUE;
537 dli = (dynlist_info_t *)on->on_bi.bi_private;
538 for ( ; dli != NULL && rs->sr_err != LDAP_COMPARE_TRUE; dli = dli->dli_next ) {
542 SlapReply r = { REP_SEARCH };
545 dynlist_sc_t dlc = { 0 };
548 int cache = op->o_do_not_cache;
549 struct berval op_dn = op->o_dn,
551 BackendDB *op_bd = op->o_bd;
553 /* fetch the entry as rootdn (a hack to see if it exists
554 * and if it has the right objectClass) */
555 op->o_do_not_cache = 1;
556 op->o_dn = op->o_bd->be_rootdn;
557 op->o_ndn = op->o_bd->be_rootndn;
558 op->o_bd = select_backend( &op->o_req_ndn, 0, 0 );
560 r.sr_err = be_entry_get_rw( op, &op->o_req_ndn,
561 dli->dli_oc, NULL, 0, &e );
563 be_entry_release_r( op, e );
565 op->o_do_not_cache = cache;
569 if ( r.sr_err != LDAP_SUCCESS ) {
573 /* if the entry has the right objectClass, generate
574 * the dynamic list and compare */
576 cb.sc_private = &dlc;
577 cb.sc_response = dynlist_sc_save_entry;
578 cb.sc_cleanup = NULL;
582 o.o_tag = LDAP_REQ_SEARCH;
584 o.ors_tlimit = SLAP_NO_LIMIT;
585 o.ors_slimit = SLAP_NO_LIMIT;
587 o.o_bd = select_backend( &o.o_req_ndn, 0, 1 );
588 if ( !o.o_bd || !o.o_bd->be_search ) {
589 return SLAP_CB_CONTINUE;
592 BER_BVSTR( &o.ors_filterstr, "(objectClass=*)" );
593 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
594 if ( o.ors_filter == NULL ) {
596 return SLAP_CB_CONTINUE;
599 o.ors_scope = LDAP_SCOPE_BASE;
600 o.ors_deref = LDAP_DEREF_NEVER;
601 an[0].an_name = op->orc_ava->aa_desc->ad_cname;
602 an[0].an_desc = op->orc_ava->aa_desc;
603 BER_BVZERO( &an[1].an_name );
607 rc = o.o_bd->be_search( &o, &r );
608 filter_free_x( &o, o.ors_filter );
614 if ( dlc.dlc_e != NULL ) {
615 r.sr_entry = dlc.dlc_e;
618 if ( r.sr_err != LDAP_SUCCESS || r.sr_entry == NULL ) {
620 return SLAP_CB_CONTINUE;
623 for ( a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
625 a = attrs_find( a->a_next, op->orc_ava->aa_desc ) )
627 /* if we're here, we got a match... */
628 rs->sr_err = LDAP_COMPARE_FALSE;
630 if ( value_find_ex( op->orc_ava->aa_desc,
631 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
632 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
633 a->a_nvals, &op->orc_ava->aa_value, op->o_tmpmemctx ) == 0 )
635 rs->sr_err = LDAP_COMPARE_TRUE;
640 if ( r.sr_flags & REP_ENTRY_MUSTBEFREED ) {
641 entry_free( r.sr_entry );
645 return SLAP_CB_CONTINUE;
649 dynlist_response( Operation *op, SlapReply *rs )
653 switch ( op->o_tag ) {
654 case LDAP_REQ_SEARCH:
655 if ( rs->sr_type == REP_SEARCH && !get_manageDSAit( op ) )
657 dli = dynlist_is_dynlist( op, rs );
659 return dynlist_send_entry( op, rs, dli );
664 case LDAP_REQ_COMPARE:
665 switch ( rs->sr_err ) {
666 /* NOTE: we waste a few cycles running the dynamic list
667 * also when the result is FALSE, which occurs if the
668 * dynamic entry itself contains the AVA attribute */
669 /* FIXME: this approach is less than optimal; a dedicated
670 * compare op should be implemented, that fetches the
671 * entry, checks if it has the appropriate objectClass
672 * and, in case, runs a compare thru all the URIs,
673 * stopping at the first positive occurrence; see ITS#3756 */
674 case LDAP_COMPARE_FALSE:
675 case LDAP_NO_SUCH_ATTRIBUTE:
676 return dynlist_compare( op, rs );
684 return SLAP_CB_CONTINUE;
688 dynlist_build_def_filter( dynlist_info_t *dli )
692 dli->dli_default_filter.bv_len = STRLENOF( "(!(objectClass=" "))" )
693 + dli->dli_oc->soc_cname.bv_len;
694 dli->dli_default_filter.bv_val = SLAP_MALLOC( dli->dli_default_filter.bv_len + 1 );
695 if ( dli->dli_default_filter.bv_val == NULL ) {
696 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: malloc failed.\n",
701 ptr = lutil_strcopy( dli->dli_default_filter.bv_val, "(!(objectClass=" );
702 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
703 ptr = lutil_strcopy( ptr, "))" );
705 assert( dli->dli_default_filter.bv_len == ptr - dli->dli_default_filter.bv_val );
719 slap_overinst *on = (slap_overinst *)be->bd_info;
723 if ( strcasecmp( argv[0], "dynlist-attrset" ) == 0 ) {
724 dynlist_info_t **dlip;
726 AttributeDescription *ad = NULL,
730 if ( argc < 3 || argc > 4 ) {
731 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
732 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
733 "invalid arg number #%d.\n",
734 fname, lineno, argc );
738 oc = oc_find( argv[1] );
740 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
741 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
742 "unable to find ObjectClass \"%s\"\n",
743 fname, lineno, argv[ 1 ] );
747 rc = slap_str2ad( argv[2], &ad, &text );
748 if ( rc != LDAP_SUCCESS ) {
749 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
750 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
751 "unable to find AttributeDescription \"%s\"\n",
752 fname, lineno, argv[2] );
756 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
757 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
758 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
759 "AttributeDescription \"%s\" "
760 "must be a subtype of \"labeledURI\"\n",
761 fname, lineno, argv[2] );
766 rc = slap_str2ad( argv[3], &member_ad, &text );
767 if ( rc != LDAP_SUCCESS ) {
768 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
769 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
770 "unable to find AttributeDescription \"%s\"\n",
771 fname, lineno, argv[3] );
776 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
777 *dlip; dlip = &(*dlip)->dli_next )
780 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
781 (*dlip)->dli_oc = oc;
782 (*dlip)->dli_ad = ad;
783 (*dlip)->dli_member_ad = member_ad;
785 if ( dynlist_build_def_filter( *dlip ) ) {
791 /* allow dyngroup syntax */
792 } else if ( strcasecmp( argv[0], "dynlist-attrpair" ) == 0 ) {
793 dynlist_info_t **dlip;
795 AttributeDescription *ad = NULL,
800 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
801 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
802 "invalid arg number #%d.\n",
803 fname, lineno, argc );
807 oc = oc_find( "groupOfURLs" );
809 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
810 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
811 "unable to find default ObjectClass \"groupOfURLs\"\n",
816 rc = slap_str2ad( argv[1], &member_ad, &text );
817 if ( rc != LDAP_SUCCESS ) {
818 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
819 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
820 "unable to find AttributeDescription \"%s\"\n",
821 fname, lineno, argv[1] );
825 rc = slap_str2ad( argv[2], &ad, &text );
826 if ( rc != LDAP_SUCCESS ) {
827 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
828 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
829 "unable to find AttributeDescription \"%s\"\n",
830 fname, lineno, argv[2] );
834 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
835 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
836 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
837 "AttributeDescription \"%s\" "
838 "must be a subtype of \"labeledURI\"\n",
839 fname, lineno, argv[2] );
844 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
845 *dlip; dlip = &(*dlip)->dli_next )
848 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
849 (*dlip)->dli_oc = oc;
850 (*dlip)->dli_ad = ad;
851 (*dlip)->dli_member_ad = member_ad;
853 if ( dynlist_build_def_filter( *dlip ) ) {
860 rc = SLAP_CONF_UNKNOWN;
873 static ConfigDriver dl_cfgen;
875 static ConfigTable dlcfg[] = {
876 { "dynlist-attrset", "group-oc> <URL-ad> <member-ad",
877 3, 4, 0, ARG_MAGIC|DL_ATTRSET, dl_cfgen,
878 "( OLcfgOvAt:8.1 NAME 'olcDLattrSet' "
879 "DESC 'Dynamic list: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
880 "EQUALITY caseIgnoreMatch "
881 "SYNTAX OMsDirectoryString "
882 "X-ORDERED 'VALUES' )",
884 { "dynlist-attrpair", "member-ad> <URL-ad",
885 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR, dl_cfgen,
887 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
890 static ConfigOCs dlocs[] = {
892 "NAME 'olcDynamicList' "
893 "DESC 'Dynamic list configuration' "
894 "SUP olcOverlayConfig "
895 "MAY olcDLattrSet )",
896 Cft_Overlay, dlcfg, NULL, NULL },
901 dl_cfgen( ConfigArgs *c )
903 slap_overinst *on = (slap_overinst *)c->bi;
904 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
908 if ( c->op == SLAP_CONFIG_EMIT ) {
911 for ( i = 0; dli; i++, dli = dli->dli_next ) {
915 assert( dli->dli_oc != NULL );
916 assert( dli->dli_ad != NULL );
918 ptr += snprintf( c->msg, sizeof( c->msg ),
919 SLAP_X_ORDERED_FMT "%s %s", i,
920 dli->dli_oc->soc_cname.bv_val,
921 dli->dli_ad->ad_cname.bv_val );
923 if ( dli->dli_member_ad != NULL ) {
926 ptr = lutil_strcopy( ptr, dli->dli_member_ad->ad_cname.bv_val );
930 bv.bv_len = ptr - bv.bv_val;
931 value_add_one( &c->rvalue_vals, &bv );
946 } else if ( c->op == LDAP_MOD_DELETE ) {
950 dynlist_info_t *dli_next;
952 for ( dli_next = dli; dli_next; dli = dli_next ) {
953 dli_next = dli->dli_next;
955 ch_free( dli->dli_default_filter.bv_val );
959 on->on_bi.bi_private = NULL;
962 dynlist_info_t **dlip;
964 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
967 if ( *dlip == NULL ) {
970 dlip = &(*dlip)->dli_next;
974 *dlip = dli->dli_next;
975 ch_free( dli->dli_default_filter.bv_val );
978 dli = (dynlist_info_t *)on->on_bi.bi_private;
991 return 1; /* FIXME */
996 dynlist_info_t **dlip,
998 ObjectClass *oc = NULL;
999 AttributeDescription *ad = NULL,
1003 oc = oc_find( c->argv[ 1 ] );
1005 snprintf( c->msg, sizeof( c->msg ),
1006 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1007 "unable to find ObjectClass \"%s\"",
1009 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1010 c->log, c->msg, 0 );
1014 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
1015 if ( rc != LDAP_SUCCESS ) {
1016 snprintf( c->msg, sizeof( c->msg ),
1017 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1018 "unable to find AttributeDescription \"%s\"",
1020 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1021 c->log, c->msg, 0 );
1025 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1026 snprintf( c->msg, sizeof( c->msg ),
1027 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1028 "AttributeDescription \"%s\" "
1029 "must be a subtype of \"labeledURI\"",
1031 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1032 c->log, c->msg, 0 );
1036 if ( c->argc == 4 ) {
1037 rc = slap_str2ad( c->argv[ 3 ], &member_ad, &text );
1038 if ( rc != LDAP_SUCCESS ) {
1039 snprintf( c->msg, sizeof( c->msg ),
1040 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1041 "unable to find AttributeDescription \"%s\"\n",
1043 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1044 c->log, c->msg, 0 );
1049 if ( c->valx > 0 ) {
1052 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1055 if ( *dlip == NULL ) {
1056 snprintf( c->msg, sizeof( c->msg ),
1057 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1058 "invalid index {%d}\n",
1060 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1061 c->log, c->msg, 0 );
1064 dlip = &(*dlip)->dli_next;
1069 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1070 *dlip; dlip = &(*dlip)->dli_next )
1074 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1076 (*dlip)->dli_oc = oc;
1077 (*dlip)->dli_ad = ad;
1078 (*dlip)->dli_member_ad = member_ad;
1079 (*dlip)->dli_next = dli_next;
1081 rc = dynlist_build_def_filter( *dlip );
1086 dynlist_info_t **dlip;
1087 ObjectClass *oc = NULL;
1088 AttributeDescription *ad = NULL,
1092 oc = oc_find( "groupOfURLs" );
1094 snprintf( c->msg, sizeof( c->msg ),
1095 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1096 "unable to find default ObjectClass \"groupOfURLs\"" );
1097 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1098 c->log, c->msg, 0 );
1102 rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text );
1103 if ( rc != LDAP_SUCCESS ) {
1104 snprintf( c->msg, sizeof( c->msg ),
1105 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1106 "unable to find AttributeDescription \"%s\"",
1108 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1109 c->log, c->msg, 0 );
1113 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
1114 if ( rc != LDAP_SUCCESS ) {
1115 snprintf( c->msg, sizeof( c->msg ),
1116 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1117 "unable to find AttributeDescription \"%s\"\n",
1119 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1120 c->log, c->msg, 0 );
1124 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1125 snprintf( c->msg, sizeof( c->msg ),
1126 "\"dynlist-attrset <oc> <URL-ad> [<member-ad>]\": "
1127 "AttributeDescription \"%s\" "
1128 "must be a subtype of \"labeledURI\"",
1130 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1131 c->log, c->msg, 0 );
1135 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1136 *dlip; dlip = &(*dlip)->dli_next )
1139 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1141 (*dlip)->dli_oc = oc;
1142 (*dlip)->dli_ad = ad;
1143 (*dlip)->dli_member_ad = member_ad;
1145 rc = dynlist_build_def_filter( *dlip );
1162 slap_overinst *on = (slap_overinst *) be->bd_info;
1163 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
1164 ObjectClass *oc = NULL;
1165 AttributeDescription *ad = NULL;
1167 if ( dli == NULL ) {
1168 dli = ch_calloc( 1, sizeof( dynlist_info_t ) );
1169 on->on_bi.bi_private = (void *)dli;
1172 for ( ; dli; dli = dli->dli_next ) {
1176 if ( dli->dli_oc == NULL ) {
1178 oc = oc_find( "groupOfURLs" );
1180 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: "
1181 "unable to fetch objectClass \"groupOfURLs\".\n",
1190 if ( dli->dli_ad == NULL ) {
1192 rc = slap_str2ad( "memberURL", &ad, &text );
1193 if ( rc != LDAP_SUCCESS ) {
1194 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: "
1195 "unable to fetch attributeDescription \"memberURL\": %d (%s).\n",
1204 rc = dynlist_build_def_filter( dli );
1217 slap_overinst *on = (slap_overinst *) be->bd_info;
1219 if ( on->on_bi.bi_private ) {
1220 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private,
1223 for ( dli_next = dli; dli_next; dli = dli_next ) {
1224 dli_next = dli->dli_next;
1226 ch_free( dli->dli_default_filter.bv_val );
1234 static slap_overinst dynlist = { { NULL } };
1236 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1238 #endif /* SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC */
1240 dynlist_initialize(void)
1242 #ifndef OL_2_2_COMPAT
1246 dynlist.on_bi.bi_type = "dynlist";
1247 #ifdef OL_2_2_COMPAT
1248 dynlist.on_bi.bi_db_config = dynlist_db_config;
1250 dynlist.on_bi.bi_db_config = config_generic_wrapper;
1252 dynlist.on_bi.bi_db_open = dynlist_db_open;
1253 dynlist.on_bi.bi_db_destroy = dynlist_db_destroy;
1255 dynlist.on_response = dynlist_response;
1257 #ifndef OL_2_2_COMPAT
1258 dynlist.on_bi.bi_cf_ocs = dlocs;
1260 rc = config_register_schema( dlcfg, dlocs );
1266 return overlay_register( &dynlist );
1269 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1271 init_module( int argc, char *argv[] )
1273 return dynlist_initialize();
1277 #endif /* SLAPD_OVER_DYNLIST */