1 /* dynlist.c - dynamic list overlay */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2009 The OpenLDAP Foundation.
6 * Portions Copyright 2004-2005 Pierangelo Masarati.
7 * Portions Copyright 2008 Emmanuel Dreyfus.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
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>.
19 * This work was initially developed by Pierangelo Masarati
20 * for SysNet s.n.c., for inclusion in OpenLDAP Software.
25 #ifdef SLAPD_OVER_DYNLIST
27 #if LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR > 3
28 #if SLAPD_OVER_DYNGROUP != SLAPD_MOD_STATIC
29 #define TAKEOVER_DYNGROUP
32 #if LDAP_VENDOR_VERSION_MINOR < 3
39 #include <ac/string.h>
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. */
54 static AttributeName anlist_no_attrs[] = {
55 { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL },
56 { BER_BVNULL, NULL, 0, NULL }
59 static AttributeName *slap_anlist_no_attrs = anlist_no_attrs;
62 static AttributeDescription *ad_dgIdentity, *ad_dgAuthz;
64 typedef struct dynlist_map_t {
65 AttributeDescription *dlm_member_ad;
66 AttributeDescription *dlm_mapped_ad;
67 struct dynlist_map_t *dlm_next;
70 typedef struct dynlist_info_t {
72 AttributeDescription *dli_ad;
73 struct dynlist_map_t *dli_dlm;
74 struct berval dli_uri;
76 struct berval dli_uri_nbase;
77 Filter *dli_uri_filter;
78 struct berval dli_default_filter;
79 struct dynlist_info_t *dli_next;
82 #define DYNLIST_USAGE \
83 "\"dynlist-attrset <oc> [uri] <URL-ad> [[<mapped-ad>:]<member-ad> ...]\": "
85 static dynlist_info_t *
86 dynlist_is_dynlist_next( Operation *op, SlapReply *rs, dynlist_info_t *old_dli )
88 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
93 if ( old_dli == NULL ) {
94 dli = (dynlist_info_t *)on->on_bi.bi_private;
97 dli = old_dli->dli_next;
100 a = attrs_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
102 /* FIXME: objectClass must be present; for non-storage
103 * backends, like back-ldap, it needs to be added
104 * to the requested attributes */
108 for ( ; dli; dli = dli->dli_next ) {
109 if ( dli->dli_lud != NULL ) {
110 /* check base and scope */
111 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
112 int d = rs->sr_entry->e_nname.bv_len - dli->dli_uri_nbase.bv_len;
118 if ( !dnIsSuffix( &rs->sr_entry->e_nname, &dli->dli_uri_nbase ) ) {
122 switch ( dli->dli_lud->lud_scope ) {
123 case LDAP_SCOPE_BASE:
129 case LDAP_SCOPE_ONELEVEL: {
132 dnParent( &rs->sr_entry->e_nname, &pdn );
133 if ( pdn.bv_len != dli->dli_uri_nbase.bv_len ) {
138 case LDAP_SCOPE_SUBORDINATE:
144 case LDAP_SCOPE_SUBTREE:
145 case LDAP_SCOPE_DEFAULT:
154 if ( dli->dli_uri_filter && test_filter( op, rs->sr_entry, dli->dli_uri_filter ) != LDAP_COMPARE_TRUE ) {
159 if ( attr_valfind( a,
160 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
161 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
162 &dli->dli_oc->soc_cname, NULL,
163 op->o_tmpmemctx ) == 0 )
173 dynlist_make_filter( Operation *op, Entry *e, const char *url, struct berval *oldf, struct berval *newf )
175 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
176 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
179 int needBrackets = 0;
181 assert( oldf != NULL );
182 assert( newf != NULL );
183 assert( !BER_BVISNULL( oldf ) );
184 assert( !BER_BVISEMPTY( oldf ) );
186 if ( oldf->bv_val[0] != '(' ) {
187 Debug( LDAP_DEBUG_ANY, "%s: dynlist, DN=\"%s\": missing brackets in URI=\"%s\" filter\n",
188 op->o_log_prefix, e->e_name.bv_val, url );
192 newf->bv_len = STRLENOF( "(&(!(objectClass=" "))" ")" )
193 + dli->dli_oc->soc_cname.bv_len + oldf->bv_len + needBrackets;
194 newf->bv_val = op->o_tmpalloc( newf->bv_len + 1, op->o_tmpmemctx );
195 if ( newf->bv_val == NULL ) {
198 ptr = lutil_strcopy( newf->bv_val, "(&(!(objectClass=" );
199 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
200 ptr = lutil_strcopy( ptr, "))" );
201 if ( needBrackets ) *ptr++ = '(';
202 ptr = lutil_strcopy( ptr, oldf->bv_val );
203 if ( needBrackets ) *ptr++ = ')';
204 ptr = lutil_strcopy( ptr, ")" );
205 newf->bv_len = ptr - newf->bv_val;
210 typedef struct dynlist_sc_t {
211 dynlist_info_t *dlc_dli;
216 dynlist_sc_update( Operation *op, SlapReply *rs )
222 AccessControlState acl_state = ACL_STATE_INIT;
227 if ( rs->sr_type != REP_SEARCH ) {
231 dlc = (dynlist_sc_t *)op->o_callback->sc_private;
235 assert( rs->sr_entry != NULL );
237 /* test access to entry */
238 if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
239 NULL, ACL_READ, NULL ) )
244 /* if there is only one member_ad, and it's not mapped,
245 * consider it as old-style member listing */
246 dlm = dlc->dlc_dli->dli_dlm;
247 if ( dlm && dlm->dlm_mapped_ad == NULL && dlm->dlm_next == NULL ) {
248 /* if access allowed, try to add values, emulating permissive
249 * control to silently ignore duplicates */
250 if ( access_allowed( op, rs->sr_entry, slap_schema.si_ad_entry,
251 NULL, ACL_READ, NULL ) )
254 const char *text = NULL;
256 struct berval vals[ 2 ], nvals[ 2 ];
258 vals[ 0 ] = rs->sr_entry->e_name;
259 BER_BVZERO( &vals[ 1 ] );
260 nvals[ 0 ] = rs->sr_entry->e_nname;
261 BER_BVZERO( &nvals[ 1 ] );
263 mod.sm_op = LDAP_MOD_ADD;
264 mod.sm_desc = dlm->dlm_member_ad;
265 mod.sm_type = dlm->dlm_member_ad->ad_cname;
266 mod.sm_values = vals;
267 mod.sm_nvalues = nvals;
270 (void)modify_add_values( e, &mod, /* permissive */ 1,
271 &text, textbuf, sizeof( textbuf ) );
278 opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, slap_bv_operational_attrs );
279 userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, slap_bv_user_attrs );
280 #else /* SLAP_OPATTRS */
281 opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
282 userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
283 #endif /* SLAP_OPATTRS */
285 for ( a = rs->sr_entry->e_attrs; a != NULL; a = a->a_next ) {
286 BerVarray vals, nvals = NULL;
288 is_oc = a->a_desc == slap_schema.si_ad_objectClass;
290 /* if attribute is not requested, skip it */
291 if ( rs->sr_attrs == NULL ) {
292 if ( is_at_operational( a->a_desc->ad_type ) ) {
297 if ( is_at_operational( a->a_desc->ad_type ) ) {
298 if ( !opattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
304 if ( !userattrs && !ad_inlist( a->a_desc, rs->sr_attrs ) )
311 /* test access to attribute */
312 if ( op->ors_attrsonly ) {
313 if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL,
314 ACL_READ, &acl_state ) )
320 /* single-value check: keep first only */
321 if ( is_at_single_value( a->a_desc->ad_type ) ) {
322 if ( attr_find( e->e_attrs, a->a_desc ) != NULL ) {
327 /* test access to attribute */
330 vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
331 if ( a->a_nvals != a->a_vals ) {
332 nvals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
335 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
337 ObjectClass *soc = oc_bvfind( &a->a_vals[i] );
339 if ( soc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) {
344 if ( access_allowed( op, rs->sr_entry, a->a_desc,
345 &a->a_nvals[i], ACL_READ, &acl_state ) )
347 vals[j] = a->a_vals[i];
349 nvals[j] = a->a_nvals[i];
355 /* if access allowed, try to add values, emulating permissive
356 * control to silently ignore duplicates */
359 const char *text = NULL;
362 AttributeDescription *ad;
364 BER_BVZERO( &vals[j] );
366 BER_BVZERO( &nvals[j] );
370 for ( dlm = dlc->dlc_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
371 if ( dlm->dlm_member_ad == a->a_desc ) {
372 if ( dlm->dlm_mapped_ad ) {
373 ad = dlm->dlm_mapped_ad;
379 mod.sm_op = LDAP_MOD_ADD;
381 mod.sm_type = ad->ad_cname;
382 mod.sm_values = vals;
383 mod.sm_nvalues = nvals;
386 (void)modify_add_values( e, &mod, /* permissive */ 1,
387 &text, textbuf, sizeof( textbuf ) );
390 op->o_tmpfree( vals, op->o_tmpmemctx );
392 op->o_tmpfree( nvals, op->o_tmpmemctx );
397 if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
398 entry_free( rs->sr_entry );
400 rs->sr_flags ^= REP_ENTRY_MUSTBEFREED;
407 dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli )
409 Attribute *a, *id = NULL;
412 SlapReply r = { REP_SEARCH };
418 dynlist_sc_t dlc = { 0 };
421 a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad );
424 return SLAP_CB_CONTINUE;
428 opattrs = ( rs->sr_attrs == NULL ) ? 0 : an_find( rs->sr_attrs, slap_bv_operational_attrs );
429 userattrs = ( rs->sr_attrs == NULL ) ? 1 : an_find( rs->sr_attrs, slap_bv_user_attrs );
430 #else /* SLAP_OPATTRS */
431 opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
432 userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
433 #endif /* SLAP_OPATTRS */
435 /* Don't generate member list if it wasn't requested */
436 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
437 AttributeDescription *ad = dlm->dlm_mapped_ad ? dlm->dlm_mapped_ad : dlm->dlm_member_ad;
438 if ( userattrs || ad_inlist( ad, rs->sr_attrs ) )
441 if ( dli->dli_dlm && !dlm )
442 return SLAP_CB_CONTINUE;
444 if ( ad_dgIdentity && ( id = attrs_find( rs->sr_entry->e_attrs, ad_dgIdentity ))) {
445 Attribute *authz = NULL;
447 /* if not rootdn and dgAuthz is present,
448 * check if user can be authorized as dgIdentity */
449 if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
450 && ( authz = attrs_find( rs->sr_entry->e_attrs, ad_dgAuthz ) ) )
452 if ( slap_sasl_matches( op, authz->a_nvals,
453 &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
455 return SLAP_CB_CONTINUE;
459 o.o_dn = id->a_vals[0];
460 o.o_ndn = id->a_nvals[0];
464 e_flags = rs->sr_flags;
465 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
466 e = entry_dup( rs->sr_entry );
467 e_flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
474 cb.sc_private = &dlc;
475 cb.sc_response = dynlist_sc_update;
476 cb.sc_cleanup = NULL;
480 o.ors_deref = LDAP_DEREF_NEVER;
482 o.ors_tlimit = SLAP_NO_LIMIT;
483 o.ors_slimit = SLAP_NO_LIMIT;
485 for ( url = a->a_nvals; !BER_BVISNULL( url ); url++ ) {
486 LDAPURLDesc *lud = NULL;
491 BER_BVZERO( &o.o_req_dn );
492 BER_BVZERO( &o.o_req_ndn );
495 BER_BVZERO( &o.ors_filterstr );
497 if ( ldap_url_parse( url->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
502 if ( lud->lud_host != NULL ) {
503 /* FIXME: host not allowed; reject as illegal? */
504 Debug( LDAP_DEBUG_ANY, "dynlist_prepare_entry(\"%s\"): "
505 "illegal URI \"%s\"\n",
506 e->e_name.bv_val, url->bv_val, 0 );
510 if ( lud->lud_dn == NULL ) {
511 /* note that an empty base is not honored in terms
512 * of defaultSearchBase, because select_backend()
513 * is not aware of the defaultSearchBase option;
514 * this can be useful in case of a database serving
515 * the empty suffix */
516 BER_BVSTR( &dn, "" );
519 ber_str2bv( lud->lud_dn, 0, 0, &dn );
521 rc = dnPrettyNormal( NULL, &dn, &o.o_req_dn, &o.o_req_ndn, op->o_tmpmemctx );
522 if ( rc != LDAP_SUCCESS ) {
526 o.ors_scope = lud->lud_scope;
528 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
529 if ( dlm->dlm_mapped_ad != NULL ) {
534 if ( dli->dli_dlm && !dlm ) {
535 /* if ( lud->lud_attrs != NULL ),
536 * the URL should be ignored */
537 o.ors_attrs = slap_anlist_no_attrs;
539 } else if ( lud->lud_attrs == NULL ) {
540 o.ors_attrs = rs->sr_attrs;
543 for ( i = 0; lud->lud_attrs[i]; i++)
546 o.ors_attrs = op->o_tmpcalloc( i + 1, sizeof( AttributeName ), op->o_tmpmemctx );
547 for ( i = 0, j = 0; lud->lud_attrs[i]; i++) {
548 const char *text = NULL;
550 ber_str2bv( lud->lud_attrs[i], 0, 0, &o.ors_attrs[j].an_name );
551 o.ors_attrs[j].an_desc = NULL;
552 (void)slap_bv2ad( &o.ors_attrs[j].an_name, &o.ors_attrs[j].an_desc, &text );
553 /* FIXME: ignore errors... */
555 if ( rs->sr_attrs == NULL ) {
556 if ( o.ors_attrs[j].an_desc != NULL &&
557 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
563 if ( o.ors_attrs[j].an_desc != NULL &&
564 is_at_operational( o.ors_attrs[j].an_desc->ad_type ) )
570 if ( !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) ) {
571 /* lookup if mapped -- linear search,
572 * not very efficient unless list
574 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
575 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) {
587 o.ors_attrs[j].an_desc != NULL &&
588 !ad_inlist( o.ors_attrs[j].an_desc, rs->sr_attrs ) )
590 /* lookup if mapped -- linear search,
591 * not very efficient unless list
593 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
594 if ( dlm->dlm_member_ad == o.ors_attrs[j].an_desc ) {
613 BER_BVZERO( &o.ors_attrs[j].an_name );
616 if ( lud->lud_filter == NULL ) {
617 ber_dupbv_x( &o.ors_filterstr,
618 &dli->dli_default_filter, op->o_tmpmemctx );
622 ber_str2bv( lud->lud_filter, 0, 0, &flt );
623 if ( dynlist_make_filter( op, rs->sr_entry, url->bv_val, &flt, &o.ors_filterstr ) ) {
628 o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
629 if ( o.ors_filter == NULL ) {
633 o.o_bd = select_backend( &o.o_req_ndn, 1 );
634 if ( o.o_bd && o.o_bd->be_search ) {
636 r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
637 #endif /* SLAP_OPATTRS */
638 (void)o.o_bd->be_search( &o, &r );
643 slap_op_groups_free( &o );
645 if ( o.ors_filter ) {
646 filter_free_x( &o, o.ors_filter, 1 );
648 if ( o.ors_attrs && o.ors_attrs != rs->sr_attrs
649 && o.ors_attrs != slap_anlist_no_attrs )
651 op->o_tmpfree( o.ors_attrs, op->o_tmpmemctx );
653 if ( !BER_BVISNULL( &o.o_req_dn ) ) {
654 op->o_tmpfree( o.o_req_dn.bv_val, op->o_tmpmemctx );
656 if ( !BER_BVISNULL( &o.o_req_ndn ) ) {
657 op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx );
659 assert( BER_BVISNULL( &o.ors_filterstr )
660 || o.ors_filterstr.bv_val != lud->lud_filter );
661 op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
662 ldap_free_urldesc( lud );
666 rs->sr_flags = e_flags;
668 return SLAP_CB_CONTINUE;
672 dynlist_sc_save_entry( Operation *op, SlapReply *rs )
674 /* save the entry in the private field of the callback,
675 * so it doesn't get freed (it's temporary!) */
676 if ( rs->sr_entry != NULL ) {
677 dynlist_sc_t *dlc = (dynlist_sc_t *)op->o_callback->sc_private;
678 dlc->dlc_e = rs->sr_entry;
686 dynlist_compare( Operation *op, SlapReply *rs )
688 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
689 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
694 for ( ; dli != NULL; dli = dli->dli_next ) {
695 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next )
696 if ( op->oq_compare.rs_ava->aa_desc == dlm->dlm_member_ad )
699 if ( dli->dli_dlm && dlm ) {
700 /* This compare is for one of the attributes we're
701 * interested in. We'll use slapd's existing dyngroup
702 * evaluator to get the answer we want.
704 BerVarray id = NULL, authz = NULL;
706 o.o_do_not_cache = 1;
708 if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn,
709 ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS )
711 /* if not rootdn and dgAuthz is present,
712 * check if user can be authorized as dgIdentity */
713 if ( ad_dgAuthz && !BER_BVISEMPTY( id ) && !be_isroot( op )
714 && backend_attribute( &o, NULL, &o.o_req_ndn,
715 ad_dgAuthz, &authz, ACL_READ ) == LDAP_SUCCESS )
718 rs->sr_err = slap_sasl_matches( op, authz,
719 &o.o_ndn, &o.o_ndn );
720 ber_bvarray_free_x( authz, op->o_tmpmemctx );
721 if ( rs->sr_err != LDAP_SUCCESS ) {
728 o.o_groups = NULL; /* authz changed, invalidate cached groups */
731 rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn,
732 &o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad );
733 switch ( rs->sr_err ) {
735 rs->sr_err = LDAP_COMPARE_TRUE;
738 case LDAP_NO_SUCH_OBJECT:
739 /* NOTE: backend_group() returns noSuchObject
740 * if op_ndn does not exist; however, since
741 * dynamic list expansion means that the
742 * member attribute is virtually present, the
743 * non-existence of the asserted value implies
744 * the assertion is FALSE rather than
746 rs->sr_err = LDAP_COMPARE_FALSE;
751 if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx );
753 return SLAP_CB_CONTINUE;
757 if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) !=
758 LDAP_SUCCESS || e == NULL )
760 return SLAP_CB_CONTINUE;
763 if ( ad_dgIdentity ) {
764 Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity );
768 /* if not rootdn and dgAuthz is present,
769 * check if user can be authorized as dgIdentity */
770 if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
771 && ( authz = attrs_find( e->e_attrs, ad_dgAuthz ) ) )
773 if ( slap_sasl_matches( op, authz->a_nvals,
774 &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
780 o.o_dn = id->a_vals[0];
781 o.o_ndn = id->a_nvals[0];
786 dli = (dynlist_info_t *)on->on_bi.bi_private;
787 for ( ; dli != NULL && rs->sr_err != LDAP_COMPARE_TRUE; dli = dli->dli_next ) {
790 SlapReply r = { REP_SEARCH };
793 dynlist_sc_t dlc = { 0 };
795 if ( !is_entry_objectclass_or_sub( e, dli->dli_oc ))
798 /* if the entry has the right objectClass, generate
799 * the dynamic list and compare */
801 cb.sc_private = &dlc;
802 cb.sc_response = dynlist_sc_save_entry;
803 cb.sc_cleanup = NULL;
807 o.o_tag = LDAP_REQ_SEARCH;
809 o.ors_tlimit = SLAP_NO_LIMIT;
810 o.ors_slimit = SLAP_NO_LIMIT;
812 o.o_bd = select_backend( &o.o_req_ndn, 1 );
813 if ( !o.o_bd || !o.o_bd->be_search ) {
817 o.ors_filterstr = *slap_filterstr_objectClass_pres;
818 o.ors_filter = (Filter *) slap_filter_objectClass_pres;
820 o.ors_scope = LDAP_SCOPE_BASE;
821 o.ors_deref = LDAP_DEREF_NEVER;
822 an[0].an_name = op->orc_ava->aa_desc->ad_cname;
823 an[0].an_desc = op->orc_ava->aa_desc;
824 BER_BVZERO( &an[1].an_name );
828 o.o_acl_priv = ACL_COMPARE;
830 rc = o.o_bd->be_search( &o, &r );
832 if ( o.o_dn.bv_val != op->o_dn.bv_val ) {
833 slap_op_groups_free( &o );
840 if ( dlc.dlc_e != NULL ) {
841 r.sr_entry = dlc.dlc_e;
844 if ( r.sr_err != LDAP_SUCCESS || r.sr_entry == NULL ) {
849 for ( a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
851 a = attrs_find( a->a_next, op->orc_ava->aa_desc ) )
853 /* if we're here, we got a match... */
854 rs->sr_err = LDAP_COMPARE_FALSE;
856 if ( attr_valfind( a,
857 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
858 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
859 &op->orc_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 )
861 rs->sr_err = LDAP_COMPARE_TRUE;
866 if ( r.sr_flags & REP_ENTRY_MUSTBEFREED ) {
867 entry_free( r.sr_entry );
869 r.sr_flags ^= REP_ENTRY_MUSTBEFREED;
875 overlay_entry_release_ov( &o, e, 0, on );
878 return SLAP_CB_CONTINUE;
882 dynlist_response( Operation *op, SlapReply *rs )
886 switch ( op->o_tag ) {
887 case LDAP_REQ_SEARCH:
888 if ( rs->sr_type == REP_SEARCH && !get_manageDSAit( op ) )
892 for ( dli = dynlist_is_dynlist_next( op, rs, NULL );
894 dli = dynlist_is_dynlist_next( op, rs, dli ) )
896 rc = dynlist_prepare_entry( op, rs, dli );
899 if ( rc != LDAP_OTHER ) {
905 case LDAP_REQ_COMPARE:
906 switch ( rs->sr_err ) {
907 /* NOTE: we waste a few cycles running the dynamic list
908 * also when the result is FALSE, which occurs if the
909 * dynamic entry itself contains the AVA attribute */
910 /* FIXME: this approach is less than optimal; a dedicated
911 * compare op should be implemented, that fetches the
912 * entry, checks if it has the appropriate objectClass
913 * and, in case, runs a compare thru all the URIs,
914 * stopping at the first positive occurrence; see ITS#3756 */
915 case LDAP_COMPARE_FALSE:
916 case LDAP_NO_SUCH_ATTRIBUTE:
917 return dynlist_compare( op, rs );
925 return SLAP_CB_CONTINUE;
929 dynlist_build_def_filter( dynlist_info_t *dli )
933 dli->dli_default_filter.bv_len = STRLENOF( "(!(objectClass=" "))" )
934 + dli->dli_oc->soc_cname.bv_len;
935 dli->dli_default_filter.bv_val = ch_malloc( dli->dli_default_filter.bv_len + 1 );
936 if ( dli->dli_default_filter.bv_val == NULL ) {
937 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: malloc failed.\n",
942 ptr = lutil_strcopy( dli->dli_default_filter.bv_val, "(!(objectClass=" );
943 ptr = lutil_strcopy( ptr, dli->dli_oc->soc_cname.bv_val );
944 ptr = lutil_strcopy( ptr, "))" );
946 assert( ptr == &dli->dli_default_filter.bv_val[dli->dli_default_filter.bv_len] );
960 slap_overinst *on = (slap_overinst *)be->bd_info;
964 if ( strcasecmp( argv[0], "dynlist-attrset" ) == 0 ) {
965 dynlist_info_t **dlip;
967 AttributeDescription *ad = NULL,
969 dynlist_map_t *dlm = NULL, *dlml = NULL;
973 Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
974 "invalid arg number #%d.\n",
975 fname, lineno, argc );
979 oc = oc_find( argv[1] );
981 Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
982 "unable to find ObjectClass \"%s\"\n",
983 fname, lineno, argv[ 1 ] );
987 rc = slap_str2ad( argv[2], &ad, &text );
988 if ( rc != LDAP_SUCCESS ) {
989 Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
990 "unable to find AttributeDescription \"%s\"\n",
991 fname, lineno, argv[2] );
995 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
996 Debug( LDAP_DEBUG_ANY, "%s: line %d: " DYNLIST_USAGE
997 "AttributeDescription \"%s\" "
998 "must be a subtype of \"labeledURI\"\n",
999 fname, lineno, argv[2] );
1003 for ( i = 3; i < argc; i++ ) {
1006 AttributeDescription *member_ad = NULL;
1007 AttributeDescription *mapped_ad = NULL;
1008 dynlist_map_t *dlmp;
1012 * If no mapped attribute is given, dn is used
1013 * for backward compatibility.
1016 if ( cp = strchr( arg, (int)':' ) != NULL ) {
1018 ber_str2bv( arg, cp - arg, 0, &bv );
1019 rc = slap_bv2ad( &bv, &mapped_ad, &text );
1020 if ( rc != LDAP_SUCCESS ) {
1021 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1023 "unable to find mapped AttributeDescription \"%s\"\n",
1024 fname, lineno, arg );
1031 rc = slap_str2ad( arg, &member_ad, &text );
1032 if ( rc != LDAP_SUCCESS ) {
1033 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1035 "unable to find AttributeDescription \"%s\"\n",
1036 fname, lineno, arg );
1040 dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1041 if ( dlm == NULL ) {
1044 dlmp->dlm_member_ad = member_ad;
1045 dlmp->dlm_mapped_ad = mapped_ad;
1046 dlmp->dlm_next = NULL;
1049 dlml->dlm_next = dlmp;
1053 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1054 *dlip; dlip = &(*dlip)->dli_next )
1057 * The same URL attribute / member attribute pair
1058 * cannot be repeated, but we enforce this only
1059 * when the member attribute is unique. Performing
1060 * the check for multiple values would require
1061 * sorting and comparing the lists, which is left
1062 * as a future improvement
1064 if ( (*dlip)->dli_ad == ad &&
1065 (*dlip)->dli_dlm->dlm_next == NULL &&
1066 dlm->dlm_next == NULL &&
1067 dlm->dlm_member_ad == (*dlip)->dli_dlm->dlm_member_ad &&
1068 dlm->dlm_mapped_ad == (*dlip)->dli_dlm->dlm_mapped_ad ) {
1069 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1071 "URL attributeDescription \"%s\" already mapped.\n",
1072 fname, lineno, ad->ad_cname.bv_val );
1074 /* make it a warning... */
1080 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1081 (*dlip)->dli_oc = oc;
1082 (*dlip)->dli_ad = ad;
1083 (*dlip)->dli_dlm = dlm;
1085 if ( dynlist_build_def_filter( *dlip ) ) {
1086 dynlist_map_t *dlm = (*dlip)->ldi_dlm;
1087 dynlist_map_t *dlm_next;
1089 while ( dlm != NULL ) {
1090 dlm_next = dlm->dlm_next;
1100 /* allow dyngroup syntax */
1101 } else if ( strcasecmp( argv[0], "dynlist-attrpair" ) == 0 ) {
1102 dynlist_info_t **dlip;
1104 AttributeDescription *ad = NULL,
1109 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1110 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1111 "invalid arg number #%d.\n",
1112 fname, lineno, argc );
1116 oc = oc_find( "groupOfURLs" );
1118 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1119 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1120 "unable to find default ObjectClass \"groupOfURLs\"\n",
1125 rc = slap_str2ad( argv[1], &member_ad, &text );
1126 if ( rc != LDAP_SUCCESS ) {
1127 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1128 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1129 "unable to find AttributeDescription \"%s\"\n",
1130 fname, lineno, argv[1] );
1134 rc = slap_str2ad( argv[2], &ad, &text );
1135 if ( rc != LDAP_SUCCESS ) {
1136 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1137 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1138 "unable to find AttributeDescription \"%s\"\n",
1139 fname, lineno, argv[2] );
1143 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1144 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1145 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1146 "AttributeDescription \"%s\" "
1147 "must be a subtype of \"labeledURI\"\n",
1148 fname, lineno, argv[2] );
1152 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1153 *dlip; dlip = &(*dlip)->dli_next )
1156 * The same URL attribute / member attribute pair
1157 * cannot be repeated, but we enforce this only
1158 * when the member attribute is unique. Performing
1159 * the check for multiple values would require
1160 * sorting and comparing the lists, which is left
1161 * as a future improvement
1163 if ( (*dlip)->dli_ad == ad &&
1164 (*dlip)->dli_dlm->dlm_next == NULL &&
1165 member_ad == (*dlip)->dli_dlm->dlm_member_ad ) {
1166 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1167 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1168 "URL attributeDescription \"%s\" already mapped.\n",
1169 fname, lineno, ad->ad_cname.bv_val );
1171 /* make it a warning... */
1177 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1178 (*dlip)->dli_oc = oc;
1179 (*dlip)->dli_ad = ad;
1180 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1181 (*dlip)->dli_dlm->dlm_member_ad = member_ad;
1182 (*dlip)->dli_dlm->dlm_mapped_ad = NULL;
1184 if ( dynlist_build_def_filter( *dlip ) ) {
1185 ch_free( (*dlip)->dli_dlm );
1192 rc = SLAP_CONF_UNKNOWN;
1206 static ConfigDriver dl_cfgen;
1208 /* XXXmanu 255 is the maximum arguments we allow. Can we go beyond? */
1209 static ConfigTable dlcfg[] = {
1210 { "dynlist-attrset", "group-oc> [uri] <URL-ad> <[mapped:]member-ad> [...]",
1211 3, 0, 0, ARG_MAGIC|DL_ATTRSET, dl_cfgen,
1212 "( OLcfgOvAt:8.1 NAME 'olcDlAttrSet' "
1213 "DESC 'Dynamic list: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1214 "EQUALITY caseIgnoreMatch "
1215 "SYNTAX OMsDirectoryString "
1216 "X-ORDERED 'VALUES' )",
1218 { "dynlist-attrpair", "member-ad> <URL-ad",
1219 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR, dl_cfgen,
1221 #ifdef TAKEOVER_DYNGROUP
1222 { "attrpair", "member-ad> <URL-ad",
1223 3, 3, 0, ARG_MAGIC|DL_ATTRPAIR_COMPAT, dl_cfgen,
1226 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1229 static ConfigOCs dlocs[] = {
1230 { "( OLcfgOvOc:8.1 "
1231 "NAME 'olcDynamicList' "
1232 "DESC 'Dynamic list configuration' "
1233 "SUP olcOverlayConfig "
1234 "MAY olcDLattrSet )",
1235 Cft_Overlay, dlcfg, NULL, NULL },
1240 dl_cfgen( ConfigArgs *c )
1242 slap_overinst *on = (slap_overinst *)c->bi;
1243 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
1247 if ( c->op == SLAP_CONFIG_EMIT ) {
1250 for ( i = 0; dli; i++, dli = dli->dli_next ) {
1252 char *ptr = c->cr_msg;
1255 assert( dli->dli_oc != NULL );
1256 assert( dli->dli_ad != NULL );
1258 /* FIXME: check buffer overflow! */
1259 ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1260 SLAP_X_ORDERED_FMT "%s", i,
1261 dli->dli_oc->soc_cname.bv_val );
1263 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1266 ptr = lutil_strncopy( ptr, dli->dli_uri.bv_val,
1267 dli->dli_uri.bv_len );
1272 ptr = lutil_strncopy( ptr, dli->dli_ad->ad_cname.bv_val,
1273 dli->dli_ad->ad_cname.bv_len );
1275 for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
1278 if ( dlm->dlm_mapped_ad ) {
1279 ptr = lutil_strcopy( ptr, dlm->dlm_mapped_ad->ad_cname.bv_val );
1284 ptr = lutil_strcopy( ptr, dlm->dlm_member_ad->ad_cname.bv_val );
1287 bv.bv_val = c->cr_msg;
1288 bv.bv_len = ptr - bv.bv_val;
1289 value_add_one( &c->rvalue_vals, &bv );
1293 case DL_ATTRPAIR_COMPAT:
1305 } else if ( c->op == LDAP_MOD_DELETE ) {
1308 if ( c->valx < 0 ) {
1309 dynlist_info_t *dli_next;
1311 for ( dli_next = dli; dli_next; dli = dli_next ) {
1312 dynlist_map_t *dlm = dli->dli_dlm;
1313 dynlist_map_t *dlm_next;
1315 dli_next = dli->dli_next;
1317 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1318 ch_free( dli->dli_uri.bv_val );
1321 if ( dli->dli_lud != NULL ) {
1322 ldap_free_urldesc( dli->dli_lud );
1325 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1326 ber_memfree( dli->dli_uri_nbase.bv_val );
1329 if ( dli->dli_uri_filter != NULL ) {
1330 filter_free( dli->dli_uri_filter );
1333 ch_free( dli->dli_default_filter.bv_val );
1335 while ( dlm != NULL ) {
1336 dlm_next = dlm->dlm_next;
1343 on->on_bi.bi_private = NULL;
1346 dynlist_info_t **dlip;
1348 dynlist_map_t *dlm_next;
1350 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1353 if ( *dlip == NULL ) {
1356 dlip = &(*dlip)->dli_next;
1360 *dlip = dli->dli_next;
1362 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1363 ch_free( dli->dli_uri.bv_val );
1366 if ( dli->dli_lud != NULL ) {
1367 ldap_free_urldesc( dli->dli_lud );
1370 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1371 ber_memfree( dli->dli_uri_nbase.bv_val );
1374 if ( dli->dli_uri_filter != NULL ) {
1375 filter_free( dli->dli_uri_filter );
1378 ch_free( dli->dli_default_filter.bv_val );
1381 while ( dlm != NULL ) {
1382 dlm_next = dlm->dlm_next;
1388 dli = (dynlist_info_t *)on->on_bi.bi_private;
1392 case DL_ATTRPAIR_COMPAT:
1407 dynlist_info_t **dlip,
1409 ObjectClass *oc = NULL;
1410 AttributeDescription *ad = NULL;
1412 LDAPURLDesc *lud = NULL;
1413 struct berval nbase = BER_BVNULL;
1414 Filter *filter = NULL;
1415 struct berval uri = BER_BVNULL;
1416 dynlist_map_t *dlm = NULL, *dlml = NULL;
1419 oc = oc_find( c->argv[ 1 ] );
1421 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1422 "unable to find ObjectClass \"%s\"",
1424 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1425 c->log, c->cr_msg, 0 );
1429 if ( strncasecmp( c->argv[ attridx ], "ldap://", STRLENOF("ldap://") ) == 0 ) {
1430 if ( ldap_url_parse( c->argv[ attridx ], &lud ) != LDAP_URL_SUCCESS ) {
1431 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1432 "unable to parse URI \"%s\"",
1433 c->argv[ attridx ] );
1438 if ( lud->lud_host != NULL ) {
1439 if ( lud->lud_host[0] == '\0' ) {
1440 ch_free( lud->lud_host );
1441 lud->lud_host = NULL;
1444 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1445 "host not allowed in URI \"%s\"",
1446 c->argv[ attridx ] );
1452 if ( lud->lud_attrs != NULL ) {
1453 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1454 "attrs not allowed in URI \"%s\"",
1455 c->argv[ attridx ] );
1460 if ( lud->lud_exts != NULL ) {
1461 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1462 "extensions not allowed in URI \"%s\"",
1463 c->argv[ attridx ] );
1468 if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' ) {
1470 ber_str2bv( lud->lud_dn, 0, 0, &dn );
1471 rc = dnNormalize( 0, NULL, NULL, &dn, &nbase, NULL );
1472 if ( rc != LDAP_SUCCESS ) {
1473 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1474 "DN normalization failed in URI \"%s\"",
1475 c->argv[ attridx ] );
1480 if ( lud->lud_filter != NULL && lud->lud_filter[ 0 ] != '\0' ) {
1481 filter = str2filter( lud->lud_filter );
1482 if ( filter == NULL ) {
1483 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1484 "filter parsing failed in URI \"%s\"",
1485 c->argv[ attridx ] );
1491 ber_str2bv( c->argv[ attridx ], 0, 1, &uri );
1496 ldap_free_urldesc( lud );
1499 if ( !BER_BVISNULL( &nbase ) ) {
1500 ber_memfree( nbase.bv_val );
1503 if ( filter != NULL ) {
1504 filter_free( filter );
1507 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1508 c->log, c->cr_msg, 0 );
1516 rc = slap_str2ad( c->argv[ attridx ], &ad, &text );
1517 if ( rc != LDAP_SUCCESS ) {
1518 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1519 "unable to find AttributeDescription \"%s\"",
1520 c->argv[ attridx ] );
1521 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1522 c->log, c->cr_msg, 0 );
1526 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1527 snprintf( c->cr_msg, sizeof( c->cr_msg ), DYNLIST_USAGE
1528 "AttributeDescription \"%s\" "
1529 "must be a subtype of \"labeledURI\"",
1530 c->argv[ attridx ] );
1531 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1532 c->log, c->cr_msg, 0 );
1538 for ( i = attridx; i < c->argc; i++ ) {
1541 AttributeDescription *member_ad = NULL;
1542 AttributeDescription *mapped_ad = NULL;
1543 dynlist_map_t *dlmp;
1547 * If no mapped attribute is given, dn is used
1548 * for backward compatibility.
1551 if ( ( cp = strchr( arg, ':' ) ) != NULL ) {
1553 ber_str2bv( arg, cp - arg, 0, &bv );
1554 rc = slap_bv2ad( &bv, &mapped_ad, &text );
1555 if ( rc != LDAP_SUCCESS ) {
1556 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1558 "unable to find mapped AttributeDescription #%d \"%s\"\n",
1559 i - 3, c->argv[ i ] );
1560 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1561 c->log, c->cr_msg, 0 );
1567 rc = slap_str2ad( arg, &member_ad, &text );
1568 if ( rc != LDAP_SUCCESS ) {
1569 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1571 "unable to find AttributeDescription #%d \"%s\"\n",
1572 i - 3, c->argv[ i ] );
1573 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1574 c->log, c->cr_msg, 0 );
1578 dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1579 if ( dlm == NULL ) {
1582 dlmp->dlm_member_ad = member_ad;
1583 dlmp->dlm_mapped_ad = mapped_ad;
1584 dlmp->dlm_next = NULL;
1587 dlml->dlm_next = dlmp;
1591 if ( c->valx > 0 ) {
1594 for ( i = 0, dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1597 if ( *dlip == NULL ) {
1598 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1600 "invalid index {%d}\n",
1602 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1603 c->log, c->cr_msg, 0 );
1606 dlip = &(*dlip)->dli_next;
1611 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1612 *dlip; dlip = &(*dlip)->dli_next )
1616 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1618 (*dlip)->dli_oc = oc;
1619 (*dlip)->dli_ad = ad;
1620 (*dlip)->dli_dlm = dlm;
1621 (*dlip)->dli_next = dli_next;
1623 (*dlip)->dli_lud = lud;
1624 (*dlip)->dli_uri_nbase = nbase;
1625 (*dlip)->dli_uri_filter = filter;
1626 (*dlip)->dli_uri = uri;
1628 rc = dynlist_build_def_filter( *dlip );
1632 case DL_ATTRPAIR_COMPAT:
1633 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1634 "warning: \"attrpair\" only supported for limited "
1635 "backward compatibility with overlay \"dyngroup\"" );
1636 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1640 dynlist_info_t **dlip;
1641 ObjectClass *oc = NULL;
1642 AttributeDescription *ad = NULL,
1646 oc = oc_find( "groupOfURLs" );
1648 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1649 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1650 "unable to find default ObjectClass \"groupOfURLs\"" );
1651 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1652 c->log, c->cr_msg, 0 );
1656 rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text );
1657 if ( rc != LDAP_SUCCESS ) {
1658 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1659 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1660 "unable to find AttributeDescription \"%s\"",
1662 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1663 c->log, c->cr_msg, 0 );
1667 rc = slap_str2ad( c->argv[ 2 ], &ad, &text );
1668 if ( rc != LDAP_SUCCESS ) {
1669 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1670 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1671 "unable to find AttributeDescription \"%s\"\n",
1673 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1674 c->log, c->cr_msg, 0 );
1678 if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1679 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1681 "AttributeDescription \"%s\" "
1682 "must be a subtype of \"labeledURI\"",
1684 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1685 c->log, c->cr_msg, 0 );
1689 for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private;
1690 *dlip; dlip = &(*dlip)->dli_next )
1693 * The same URL attribute / member attribute pair
1694 * cannot be repeated, but we enforce this only
1695 * when the member attribute is unique. Performing
1696 * the check for multiple values would require
1697 * sorting and comparing the lists, which is left
1698 * as a future improvement
1700 if ( (*dlip)->dli_ad == ad &&
1701 (*dlip)->dli_dlm->dlm_next == NULL &&
1702 member_ad == (*dlip)->dli_dlm->dlm_member_ad ) {
1703 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1704 "\"dynlist-attrpair <member-ad> <URL-ad>\": "
1705 "URL attributeDescription \"%s\" already mapped.\n",
1706 ad->ad_cname.bv_val );
1707 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1708 c->log, c->cr_msg, 0 );
1710 /* make it a warning... */
1716 *dlip = (dynlist_info_t *)ch_calloc( 1, sizeof( dynlist_info_t ) );
1718 (*dlip)->dli_oc = oc;
1719 (*dlip)->dli_ad = ad;
1720 (*dlip)->dli_dlm = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
1721 (*dlip)->dli_dlm->dlm_member_ad = member_ad;
1722 (*dlip)->dli_dlm->dlm_mapped_ad = NULL;
1724 rc = dynlist_build_def_filter( *dlip );
1742 slap_overinst *on = (slap_overinst *) be->bd_info;
1743 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private;
1744 ObjectClass *oc = NULL;
1745 AttributeDescription *ad = NULL;
1749 if ( dli == NULL ) {
1750 dli = ch_calloc( 1, sizeof( dynlist_info_t ) );
1751 on->on_bi.bi_private = (void *)dli;
1754 for ( ; dli; dli = dli->dli_next ) {
1755 if ( dli->dli_oc == NULL ) {
1757 oc = oc_find( "groupOfURLs" );
1759 snprintf( cr->msg, sizeof( cr->msg),
1760 "unable to fetch objectClass \"groupOfURLs\"" );
1761 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1769 if ( dli->dli_ad == NULL ) {
1771 rc = slap_str2ad( "memberURL", &ad, &text );
1772 if ( rc != LDAP_SUCCESS ) {
1773 snprintf( cr->msg, sizeof( cr->msg),
1774 "unable to fetch attributeDescription \"memberURL\": %d (%s)",
1776 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 );
1784 if ( BER_BVISNULL( &dli->dli_default_filter ) ) {
1785 rc = dynlist_build_def_filter( dli );
1792 if ( ad_dgIdentity == NULL ) {
1793 rc = slap_str2ad( "dgIdentity", &ad_dgIdentity, &text );
1794 if ( rc != LDAP_SUCCESS ) {
1795 snprintf( cr->msg, sizeof( cr->msg),
1796 "unable to fetch attributeDescription \"dgIdentity\": %d (%s)",
1798 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 );
1799 /* Just a warning */
1803 if ( ad_dgAuthz == NULL ) {
1804 rc = slap_str2ad( "dgAuthz", &ad_dgAuthz, &text );
1805 if ( rc != LDAP_SUCCESS ) {
1806 snprintf( cr->msg, sizeof( cr->msg),
1807 "unable to fetch attributeDescription \"dgAuthz\": %d (%s)",
1809 Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 );
1810 /* Just a warning */
1822 slap_overinst *on = (slap_overinst *) be->bd_info;
1824 if ( on->on_bi.bi_private ) {
1825 dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private,
1828 for ( dli_next = dli; dli_next; dli = dli_next ) {
1830 dynlist_map_t *dlm_next;
1832 dli_next = dli->dli_next;
1834 if ( !BER_BVISNULL( &dli->dli_uri ) ) {
1835 ch_free( dli->dli_uri.bv_val );
1838 if ( dli->dli_lud != NULL ) {
1839 ldap_free_urldesc( dli->dli_lud );
1842 if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
1843 ber_memfree( dli->dli_uri_nbase.bv_val );
1846 if ( dli->dli_uri_filter != NULL ) {
1847 filter_free( dli->dli_uri_filter );
1850 ch_free( dli->dli_default_filter.bv_val );
1853 while ( dlm != NULL ) {
1854 dlm_next = dlm->dlm_next;
1865 static slap_overinst dynlist = { { NULL } };
1866 #ifdef TAKEOVER_DYNGROUP
1867 static char *obsolete_names[] = {
1873 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1875 #endif /* SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC */
1877 dynlist_initialize(void)
1879 #ifndef OL_2_2_COMPAT
1883 dynlist.on_bi.bi_type = "dynlist";
1885 #ifdef TAKEOVER_DYNGROUP
1886 /* makes dynlist incompatible with dyngroup */
1887 dynlist.on_bi.bi_obsolete_names = obsolete_names;
1890 #ifdef OL_2_2_COMPAT
1891 dynlist.on_bi.bi_db_config = dynlist_db_config;
1893 dynlist.on_bi.bi_db_config = config_generic_wrapper;
1895 dynlist.on_bi.bi_db_open = dynlist_db_open;
1896 dynlist.on_bi.bi_db_destroy = dynlist_db_destroy;
1898 dynlist.on_response = dynlist_response;
1900 #ifndef OL_2_2_COMPAT
1901 dynlist.on_bi.bi_cf_ocs = dlocs;
1903 rc = config_register_schema( dlcfg, dlocs );
1909 return overlay_register( &dynlist );
1912 #if SLAPD_OVER_DYNLIST == SLAPD_MOD_DYNAMIC
1914 init_module( int argc, char *argv[] )
1916 return dynlist_initialize();
1920 #endif /* SLAPD_OVER_DYNLIST */