From: Pierangelo Masarati Date: Sun, 25 Jul 2004 23:16:40 +0000 (+0000) Subject: slightly rework user/operational attributes handling (including fixing a bug in the... X-Git-Tag: OPENDLAP_REL_ENG_2_2_MP~21 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=9f6f5491fe55d31cc5eceab59be6bcdc47ea4282;p=openldap slightly rework user/operational attributes handling (including fixing a bug in the logic of the previous change to backend_operational()); cleanup; more improvements to slapo-rwm and back-relay --- diff --git a/doc/man/man5/slapd-relay.5 b/doc/man/man5/slapd-relay.5 index ad8466eae2..5a165f3b5b 100644 --- a/doc/man/man5/slapd-relay.5 +++ b/doc/man/man5/slapd-relay.5 @@ -17,34 +17,63 @@ It requires the .LP This backend and the above mentioned overlay are experimental. .SH CONFIGURATION -These +The following .B slapd.conf -options apply to the relay backend database. +directives apply to the relay backend database. That is, they must follow a "database relay" line and come before any subsequent "backend" or "database" lines. Other database options are described in the .BR slapd.conf (5) -manual page. +manual page; only the +.B suffix +directive is required by the +.I relay +backend. .TP .B relay [massage] The naming context of the database that is presented under a virtual naming context. -The presence of the directive implies that one single database +The presence of this directive implies that one specific database, +i.e. the one serving the +.BR "real naming context" , will be presented under a virtual naming context. This directive automatically instantiates the -.B rwm -.BR overlay . +.IR "rwm overlay" . If the optional .B massage keyword is present, the suffix massaging is automatically -configured as well. +configured as well; otherwise, specific massaging instructions +are required by means of the +.I rewrite +directives described in +.BR slapo-rwm (5). + +.SH ACCESS RULES +One important issue is that access rules are based on the identity +that issued the operation. +After massaging from the virtual to the real naming context, the +frontend sees the operation as performed by the identty in the +real naming context. +Moreover, since +.B back-relay +bypasses the real database frontend operations by short-circuiting +operations thru the internal backend API, the original database +access rules do not apply but in selected cases, i.e. when the +backend itself applies access control. +As a consequence, the instances of the relay database must provide +own access rules that are consistent with those of the original +database, possibly adding further specific restrictions. +So, access rules in the +.B relay +database must refer to identities in the real naming context. +Examples are reported in the EXAMPLES section. .SH SCENARIOS .LP If no .B relay directive is given, the -.B relay +.I relay database does not refer to any specific database, but the most appropriate one is looked-up after rewriting the request DN for the operation that is being handled. @@ -52,7 +81,8 @@ for the operation that is being handled. This allows to write carefully crafted rewrite rules that cause some of the requests to be directed to one database, and some to another; e.g., authentication can be mapped to one -database, and searches to another and so. +database, and searches to another, or different target databases +can be selected based on the DN of the request, and so. .LP Another possibility is to map the same operation to different databases based on details of the virtual naming context, @@ -61,7 +91,7 @@ e.g. groups on one database and persons on another. .SH Caveats The .B rwm overlay -is far from complete. +is experimental. .LP .SH EXAMPLES To implement a plain virtual naming context mapping @@ -84,6 +114,10 @@ that looks up the real naming context for each operation, use "dc=real,dc=naming,dc=context" .fi .LP +This is useful, for instance, to relay different databases that +share the terminal portion of the naming context (the one that +is rewritten). +.LP To implement the old-fashioned suffixalias, e.g. mapping the virtual to the real naming context, but not the results back from the real to the virtual naming context, use @@ -95,11 +129,11 @@ back from the real to the virtual naming context, use rewriteEngine on rewriteContext default rewriteRule "dc=virtual,dc=naming,dc=context" - "dc=real,dc=naming,dc=context" ":" - rewriteRule searchFilter - rewriteRule searchResult - rewriteRule searchResultAttrDN - rewriteRule matchedDN + "dc=real,dc=naming,dc=context" ":@" + rewriteContext searchFilter + rewriteContext searchEntryDN + rewriteContext searchAttrDN + rewriteContext matchedDN .fi .LP Note that the virtual database is bound to a single real database, @@ -108,10 +142,45 @@ so the is automatically instantiated, but the rewrite rules are written explicitly to map all the virtual to real naming context data flow, but none of the real to virtual. +.LP +Access rules: +.LP +.nf + database bdb + suffix "dc=example,dc=com" + # skip... + access to dn.subtree="dc=example,dc=com" + by dn.exact="cn=Supervisor,dc=example,dc=com" write + by * read + + database relay + suffix "o=Example,c=US" + relay "dc=example,dc=com" massage + # skip ... + access to dn.subtree="o=Example,c=US" + by dn.exact="cn=Supervisor,dc=example,dc=com" write + by dn.exact="cn=Relay Supervisor,dc=example,dc=com" write + by * read +.fi +.LP +Note that, in both databases, the identities (the +.B +clause) are in the +.BR "real naming context" , +i.e. +.BR "`dc=example,dc=com'" , +while the targets (the +.B +clause) are in the +.B real +and in the +.BR "virtual naming context" , +respectively. .SH FILES .TP ETCDIR/slapd.conf default slapd configuration file .SH SEE ALSO .BR slapd.conf (5), +.BR slapo-rwm (5), .BR slapd (8). diff --git a/doc/man/man5/slapo-rwm.5 b/doc/man/man5/slapo-rwm.5 index 1541477ebe..658ee218da 100644 --- a/doc/man/man5/slapo-rwm.5 +++ b/doc/man/man5/slapo-rwm.5 @@ -52,6 +52,15 @@ with .IR "distinguishedName syntax" , requires the knowledge of the attributeType syntax. See the REWRITING section for details. +.LP +Note that when mapping DN-valued attributes from local to remote, +first the DN is rewritten, and then the attributeType is mapped; +while mapping from remote to local, first the attributeType is mapped, +and then the DN is rewritten. +As such, it is important that the local attributeType is appropriately +defined as using the distinguishedName syntax. +Also, note that there are DN-related syntaxes, like nameAndOptionalUID, +whose values are currenlty not rewritten. .SH SUFFIX MASSAGING A basic feature of the .B rwm @@ -287,13 +296,13 @@ searchFilterAttrDN search compareDN compare compareAttrDN compare AVA addDN add -addAttrDN add AVA +addAttrDN add AVA (including "ref") modifyDN modify -modifyAttrDN modify AVA +modifyAttrDN modify AVA (including "ref") modrDN modrdn newSuperiorDN modrdn deleteDN delete -exopPasswdDN passwd exop DN if proxy +exopPasswdDN passwd exop DN .fi .RE .LP @@ -308,6 +317,8 @@ searchAttrDN search AVA (only if defined; defaults attributes of search results) matchedDN all ops (only if applicable; defaults to searchEntryDN) +referralDN all ops (only if applicable; defaults + to searchEntryDN) .fi .RE .LP diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c index afee05201a..762c90cb6f 100644 --- a/servers/slapd/attr.c +++ b/servers/slapd/attr.c @@ -44,8 +44,9 @@ void attr_free( Attribute *a ) { + if ( a->a_nvals && a->a_nvals != a->a_vals ) + ber_bvarray_free( a->a_nvals ); ber_bvarray_free( a->a_vals ); - if (a->a_nvals != a->a_vals) ber_bvarray_free( a->a_nvals ); free( a ); } diff --git a/servers/slapd/back-bdb/operational.c b/servers/slapd/back-bdb/operational.c index 5b72c32f03..3ff7aa2bc9 100644 --- a/servers/slapd/back-bdb/operational.c +++ b/servers/slapd/back-bdb/operational.c @@ -100,7 +100,7 @@ bdb_operational( for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) /* just count */ ; - if ( rs->sr_opattrs == SLAP_OPATTRS || + if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) { int hasSubordinates; diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 5d83ca441e..753d7fa6ab 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -41,8 +41,6 @@ ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent, struct berval *bdn, int flags ); #define LDAP_BUILD_ENTRY_PRIVATE 0x01 -static struct berval dummy = BER_BVNULL; - int ldap_back_search( Operation *op, @@ -200,7 +198,7 @@ fail:; ent.e_attrs = a->a_next; v = a->a_vals; - if ( a->a_vals != &dummy ) { + if ( a->a_vals != &slap_dummy_bv ) { ber_bvarray_free(a->a_vals); } if ( a->a_nvals != v ) { @@ -453,7 +451,7 @@ ldap_build_entry( * values result filter */ if ( private ) { - attr->a_vals = &dummy; + attr->a_vals = &slap_dummy_bv; } else { attr->a_vals = ch_malloc( sizeof( struct berval ) ); BER_BVZERO( &attr->a_vals[0] ); diff --git a/servers/slapd/back-ldap/unbind.c b/servers/slapd/back-ldap/unbind.c index d2d416a569..66e7139409 100644 --- a/servers/slapd/back-ldap/unbind.c +++ b/servers/slapd/back-ldap/unbind.c @@ -38,7 +38,7 @@ ldap_back_conn_destroy( ) { struct ldapinfo *li = (struct ldapinfo *) be->be_private; - struct ldapconn *lc, lc_curr; + struct ldapconn *lc = NULL, lc_curr; #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, INFO, @@ -56,6 +56,13 @@ ldap_back_conn_destroy( lc = avl_delete( &li->conntree, (caddr_t)&lc_curr, ldap_back_conn_cmp ); ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); +#ifdef ENABLE_REWRITE + /* + * Cleanup rewrite session + */ + rewrite_session_delete( li->rwmap.rwm_rw, conn ); +#endif /* ENABLE_REWRITE */ + if (lc) { #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, DETAIL1, @@ -67,13 +74,6 @@ ldap_back_conn_destroy( lc->conn->c_connid, 0, 0 ); #endif -#ifdef ENABLE_REWRITE - /* - * Cleanup rewrite session - */ - rewrite_session_delete( li->rwmap.rwm_rw, conn ); -#endif /* ENABLE_REWRITE */ - /* * Needs a test because the handler may be corrupted, * and calling ldap_unbind on a corrupted header results diff --git a/servers/slapd/back-ldbm/operational.c b/servers/slapd/back-ldbm/operational.c index e3070e5e19..de927c72bd 100644 --- a/servers/slapd/back-ldbm/operational.c +++ b/servers/slapd/back-ldbm/operational.c @@ -60,7 +60,7 @@ ldbm_back_operational( for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) /* just count */ ; - if ( rs->sr_opattrs == SLAP_OPATTRS || + if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) { int hs; diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index 1a2bf3d85d..91311fbe51 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -556,7 +556,6 @@ meta_send_entry( Entry ent = {0}; BerElement ber = *e->lm_ber; Attribute *attr, **attrp; - struct berval dummy = BER_BVNULL; struct berval *bv, bdn; const char *text; dncookie dc; @@ -652,7 +651,7 @@ meta_send_entry( if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR || attr->a_vals == NULL ) { - attr->a_vals = &dummy; + attr->a_vals = &slap_dummy_bv; } else if ( attr->a_desc == slap_schema.si_ad_objectClass || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { @@ -724,7 +723,7 @@ meta_send_entry( while ( ent.e_attrs ) { attr = ent.e_attrs; ent.e_attrs = attr->a_next; - if ( attr->a_vals != &dummy ) { + if ( attr->a_vals != &slap_dummy_bv ) { ber_bvarray_free( attr->a_vals ); } free( attr ); diff --git a/servers/slapd/back-monitor/operational.c b/servers/slapd/back-monitor/operational.c index 3fc3d9689c..6c78297a85 100644 --- a/servers/slapd/back-monitor/operational.c +++ b/servers/slapd/back-monitor/operational.c @@ -46,7 +46,7 @@ monitor_back_operational( for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) /* just count */ ; - if ( rs->sr_opattrs == SLAP_OPATTRS || + if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) { int hs; diff --git a/servers/slapd/back-sql/compare.c b/servers/slapd/back-sql/compare.c index 4a32a0e279..b5a4582a81 100644 --- a/servers/slapd/back-sql/compare.c +++ b/servers/slapd/back-sql/compare.c @@ -95,7 +95,7 @@ backsql_compare( Operation *op, SlapReply *rs ) nrs.sr_attrs = anlist; nrs.sr_entry = &user_entry; - nrs.sr_opattrs = SLAP_OPATTRS_NO; + nrs.sr_attr_flags = SLAP_OPATTRS_NO; nrs.sr_operational_attrs = NULL; rs->sr_err = backsql_operational( op, &nrs ); diff --git a/servers/slapd/back-sql/operational.c b/servers/slapd/back-sql/operational.c index 0f66e1495c..7f70185734 100644 --- a/servers/slapd/back-sql/operational.c +++ b/servers/slapd/back-sql/operational.c @@ -49,7 +49,7 @@ backsql_operational( for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) /* just count */ ; - if ( ( rs->sr_opattrs == SLAP_OPATTRS || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) + if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL ) { rc = backsql_get_db_conn( op, &dbh ); diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 59a1267f67..3524370b4e 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -1502,19 +1502,25 @@ int backend_operational( * and the backend supports specific operational attributes, * add them to the attribute list */ - if ( rs->sr_opattrs == SLAP_OPATTRS || ( op->ors_attrs && + if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( op->ors_attrs && ad_inlist( slap_schema.si_ad_subschemaSubentry, op->ors_attrs )) ) { *ap = slap_operational_subschemaSubentry( op->o_bd ); ap = &(*ap)->a_next; } - if ( ( rs->sr_opattrs == SLAP_OPATTRS || op->ors_attrs ) && op->o_bd && + if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || op->ors_attrs ) && op->o_bd && op->o_bd->be_operational != NULL ) { + Attribute *a; + + a = rs->sr_operational_attrs; rs->sr_operational_attrs = NULL; rc = op->o_bd->be_operational( op, rs ); *ap = rs->sr_operational_attrs; + if ( a != NULL ) { + rs->sr_operational_attrs = a; + } for ( ; *ap; ap = &(*ap)->a_next ) /* just count them */ ; diff --git a/servers/slapd/overlays/rwm.c b/servers/slapd/overlays/rwm.c index f5c05dcd27..f1bf2fdce7 100644 --- a/servers/slapd/overlays/rwm.c +++ b/servers/slapd/overlays/rwm.c @@ -40,7 +40,7 @@ rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie ) dncookie dc; /* - * Rewrite the bind dn if needed + * Rewrite the dn if needed */ dc.rwmap = rwmap; #ifdef ENABLE_REWRITE @@ -73,14 +73,11 @@ rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie ) op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); if ( dnp ) { op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); - } - - op->o_req_ndn = ndn; - if ( dnp ) { op->o_req_dn = dn; } else { op->o_req_dn = ndn; } + op->o_req_ndn = ndn; return LDAP_SUCCESS; } @@ -110,8 +107,8 @@ rwm_add( Operation *op, SlapReply *rs ) } if ( olddn != op->o_req_dn.bv_val ) { - ber_memfree( op->ora_e->e_name.bv_val ); - ber_memfree( op->ora_e->e_nname.bv_val ); + ch_free( op->ora_e->e_name.bv_val ); + ch_free( op->ora_e->e_nname.bv_val ); ber_dupbv( &op->ora_e->e_name, &op->o_req_dn ); ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn ); @@ -151,8 +148,23 @@ rwm_add( Operation *op, SlapReply *rs ) if ( rc ) { goto cleanup_attr; } + + } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) { +#ifdef ENABLE_REWRITE + rc = rwm_referral_rewrite( op, rs, "addAttrDN", + (*ap)->a_vals, + (*ap)->a_nvals ? &(*ap)->a_nvals : NULL ); +#else + rc = 1; + rc = rwm_referral_rewrite( op, rs, &rc, (*ap)->a_vals, + (*ap)->a_nvals ? &(*ap)->a_nvals : NULL ); +#endif + if ( rc != LDAP_SUCCESS ) { + goto cleanup_attr; + } } + next_attr:; ap = &(*ap)->a_next; continue; @@ -261,13 +273,18 @@ rwm_compare( Operation *op, SlapReply *rs ) } if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) { + struct berval *mapped_valsp[2]; + + mapped_valsp[0] = &mapped_vals[0]; + mapped_valsp[1] = &mapped_vals[1]; + mapped_vals[0] = op->orc_ava->aa_value; #ifdef ENABLE_REWRITE - rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", mapped_vals, NULL ); + rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp ); #else rc = 1; - rc = rwm_dnattr_rewrite( op, rs, &rc, mapped_vals, NULL ); + rc = rwm_dnattr_rewrite( op, rs, &rc, NULL, mapped_valsp ); #endif if ( rc != LDAP_SUCCESS ) { @@ -276,10 +293,7 @@ rwm_compare( Operation *op, SlapReply *rs ) return -1; } - if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) { - free( op->orc_ava->aa_value.bv_val ); - op->orc_ava->aa_value = mapped_vals[0]; - } + op->orc_ava->aa_value = mapped_vals[0]; } } @@ -397,7 +411,7 @@ rwm_modify( Operation *op, SlapReply *rs ) slap_schema.si_syn_distinguishedName ) { #ifdef ENABLE_REWRITE - rc = rwm_dnattr_rewrite( op, rs, "modifyDN", + rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN", (*mlp)->sml_values, (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL ); #else @@ -406,6 +420,20 @@ rwm_modify( Operation *op, SlapReply *rs ) (*mlp)->sml_values, (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL ); #endif + } else if ( (*mlp)->sml_desc == slap_schema.si_ad_ref ) { +#ifdef ENABLE_REWRITE + rc = rwm_referral_rewrite( op, rs, "modifyAttrDN", + (*mlp)->sml_values, + (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL ); +#else + rc = 1; + rc = rwm_referral_rewrite( op, rs, &rc, + (*mlp)->sml_values, + (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL ); +#endif + if ( rc != LDAP_SUCCESS ) { + goto cleanup_mod; + } } if ( rc != LDAP_SUCCESS ) { @@ -470,6 +498,9 @@ rwm_modrdn( Operation *op, SlapReply *rs ) } } + /* + * Rewrite the dn, if needed + */ #ifdef ENABLE_REWRITE rc = rwm_op_dn_massage( op, rs, "renameDN" ); #else @@ -539,7 +570,7 @@ rwm_search( Operation *op, SlapReply *rs ) } /* - * Rewrite the bind dn if needed + * Rewrite the dn if needed */ dc.rwmap = rwmap; #ifdef ENABLE_REWRITE @@ -698,13 +729,12 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first ) Attribute **ap; /* - * Rewrite the dn of the result, if needed + * Rewrite the dn attrs, if needed */ dc.rwmap = rwmap; #ifdef ENABLE_REWRITE dc.conn = op->o_conn; dc.rs = NULL; - dc.ctx = "searchAttrDN"; #else dc.tofrom = 0; dc.normalized = 0; @@ -728,11 +758,13 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first ) int last; Attribute *a; - if ( rs->sr_opattrs == SLAP_OPATTRS && is_at_operational( (*ap)->a_desc->ad_type ) ) + if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) ) { /* go on */ ; - } else if ( op->ors_attrs != NULL && !ad_inlist( (*ap)->a_desc, op->ors_attrs ) ) + } else if ( op->ors_attrs != NULL && + !SLAP_USERATTRS( rs->sr_attr_flags ) && + !ad_inlist( (*ap)->a_desc, op->ors_attrs ) ) { goto cleanup_attr; } @@ -781,7 +813,7 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first ) * the value is replaced by * ch_alloc'ed memory */ - free( bv[0].bv_val ); + ch_free( bv[0].bv_val ); ber_dupbv( &bv[0], &mapped ); } } @@ -801,10 +833,22 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first ) } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) { +#ifdef ENABLE_REWRITE + dc.ctx = "searchAttrDN"; +#endif rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals ); if ( rc != LDAP_SUCCESS ) { goto cleanup_attr; } + + } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) { +#ifdef ENABLE_REWRITE + dc.ctx = "searchAttrDN"; +#endif + rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup_attr; + } } if ( m != NULL ) { @@ -882,12 +926,13 @@ rwm_send_entry( Operation *op, SlapReply *rs ) */ rc = rwm_dn_massage( &dc, &e->e_name, &dn, &ndn ); if ( rc != LDAP_SUCCESS ) { + rc = 1; goto fail; } if ( e->e_name.bv_val != dn.bv_val ) { - free( e->e_name.bv_val ); - free( e->e_nname.bv_val ); + ch_free( e->e_name.bv_val ); + ch_free( e->e_nname.bv_val ); e->e_name = dn; e->e_nname = ndn; @@ -899,7 +944,7 @@ rwm_send_entry( Operation *op, SlapReply *rs ) /* FIXME: the entries are in the remote mapping form; * so we need to select those attributes we are willing * to return, and remap them accordingly */ - rwm_attrs( op, rs, &e->e_attrs ); + (void)rwm_attrs( op, rs, &e->e_attrs ); rs->sr_entry = e; rs->sr_flags = flags; @@ -1060,6 +1105,10 @@ rwm_m_config( static int rwm_response( Operation *op, SlapReply *rs ) { + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + int rc; if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) { @@ -1083,6 +1132,27 @@ rwm_response( Operation *op, SlapReply *rs ) case LDAP_REQ_MODIFY: case LDAP_REQ_COMPARE: case LDAP_REQ_EXTENDED: + if ( rs->sr_ref ) { + dncookie dc; + + /* + * Rewrite the dn of the referrals, if needed + */ + dc.rwmap = rwmap; +#ifdef ENABLE_REWRITE + dc.conn = op->o_conn; + dc.rs = NULL; + dc.ctx = "referralDN"; +#else + dc.tofrom = 0; + dc.normalized = 0; +#endif + rc = rwm_referral_result_rewrite( &dc, rs->sr_ref ); + if ( rc != LDAP_SUCCESS ) { + rc = 1; + break; + } + } rc = rwm_matched( op, rs ); break; diff --git a/servers/slapd/overlays/rwm.h b/servers/slapd/overlays/rwm.h index 9d3cf31f41..3bdee4f656 100644 --- a/servers/slapd/overlays/rwm.h +++ b/servers/slapd/overlays/rwm.h @@ -156,7 +156,14 @@ extern int rwm_dnattr_rewrite( void *cookie, BerVarray a_vals, BerVarray *pa_nvals ); +extern int rwm_referral_rewrite( + Operation *op, + SlapReply *rs, + void *cookie, + BerVarray a_vals, + BerVarray *pa_nvals ); extern int rwm_dnattr_result_rewrite( dncookie *dc, BerVarray a_vals ); +extern int rwm_referral_result_rewrite( dncookie *dc, BerVarray a_vals ); LDAP_END_DECL diff --git a/servers/slapd/overlays/rwmconf.c b/servers/slapd/overlays/rwmconf.c index be1e7f870e..f252298826 100644 --- a/servers/slapd/overlays/rwmconf.c +++ b/servers/slapd/overlays/rwmconf.c @@ -244,9 +244,12 @@ rwm_suffix_massage_regexize( const char *s ) p = r + 1, i++ ) ; - res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 ); + res = ch_calloc( sizeof( char ), strlen( s ) + + STRLENOF( "((.+),)?" ) + + STRLENOF( "[ ]?" ) * i + + STRLENOF( "$" ) + 1 ); - ptr = lutil_strcopy( res, "(.*)" ); + ptr = lutil_strcopy( res, "((.+),)?" ); for ( i = 0, p = s; ( r = strchr( p, ',' ) ) != NULL; p = r + 1 , i++ ) { @@ -257,7 +260,9 @@ rwm_suffix_massage_regexize( const char *s ) r++; } } - lutil_strcopy( ptr, p ); + ptr = lutil_strcopy( ptr, p ); + ptr[0] = '$'; + ptr[1] = '\0'; return res; } @@ -333,6 +338,13 @@ rwm_suffix_massage_config( rargv[ 4 ] = NULL; rewrite_parse( info, "", ++line, 4, rargv ); + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "referralDN"; + rargv[ 2 ] = "alias"; + rargv[ 3 ] = "searchEntryDN"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "", ++line, 4, rargv ); + rargv[ 0 ] = "rewriteContext"; rargv[ 1 ] = "searchAttrDN"; rargv[ 2 ] = "alias"; diff --git a/servers/slapd/overlays/rwmdn.c b/servers/slapd/overlays/rwmdn.c index 85c929b2c3..4892e4365e 100644 --- a/servers/slapd/overlays/rwmdn.c +++ b/servers/slapd/overlays/rwmdn.c @@ -48,6 +48,12 @@ rwm_dn_massage( int rc = 0; struct berval mdn; + assert( in ); + + if ( dn == NULL && ndn == NULL ) { + return LDAP_OTHER; + } + rc = rewrite_session( dc->rwmap->rwm_rw, dc->ctx, ( in->bv_len ? in->bv_val : "" ), dc->conn, &mdn.bv_val ); @@ -74,9 +80,13 @@ rwm_dn_massage( } else { /* we assume the input string is already in pretty form, * and that the normalized version is already available */ - *dn = *in; - if ( ndn != NULL ) { - BER_BVZERO( ndn ); + if ( dn ) { + *dn = *in; + if ( ndn ) { + BER_BVZERO( ndn ); + } + } else { + *ndn = *in; } rc = LDAP_SUCCESS; } @@ -84,11 +94,11 @@ rwm_dn_massage( #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, DETAIL1, "[rw] %s: \"%s\" -> \"%s\"\n", - dc->ctx, in->bv_val, dn->bv_val ); + dc->ctx, in->bv_val, dn ? dn->bv_val : ndn->bv_val ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "[rw] %s: \"%s\" -> \"%s\"\n", - dc->ctx, in->bv_val, dn->bv_val ); + dc->ctx, in->bv_val, dn ? dn->bv_val : ndn->bv_val ); #endif /* !NEW_LOGGING */ break; @@ -131,15 +141,29 @@ rwm_dn_massage( normal = BER_BVNULL, *in = tmpin; - assert( dn ); + if ( dn == NULL && ndn == NULL ) { + return LDAP_OTHER; + } if ( in == NULL || BER_BVISNULL( in ) ) { - dn->bv_val = NULL; - dn->bv_len = 0; + if ( dn ) { + BER_BVZERO( dn ); + } + if ( ndn ) { + BER_BVZERO( ndn ); + } return LDAP_SUCCESS; } + if ( dc->rwmap == NULL || dc->rwmap->rwm_suffix_massage == NULL ) { - *dn = *in; + if ( dn ) { + *dn = *in; + if ( ndn ) { + BER_BVZERO( ndn ); + } + } else { + *ndn = *in; + } return LDAP_SUCCESS; } @@ -170,7 +194,7 @@ rwm_dn_massage( return rc; } - if ( dc->normalized && !BER_BVISNULL( &normal) ) { + if ( dc->normalized && !BER_BVISNULL( &normal ) ) { in = &normal; } else if ( !dc->normalized && !BER_BVISNULL( &pretty ) ) { @@ -197,20 +221,31 @@ rwm_dn_massage( } if ( !strcmp( dc->rwmap->rwm_suffix_massage[i+src].bv_val, &in->bv_val[diff] ) ) { - dn->bv_len = diff + dc->rwmap->rwm_suffix_massage[i+dst].bv_len; - dn->bv_val = ch_malloc( dn->bv_len + 1 ); - strncpy( dn->bv_val, in->bv_val, diff ); - strcpy( &dn->bv_val[diff], dc->rwmap->rwm_suffix_massage[i+dst].bv_val ); + struct berval *out; + + if ( dn ) { + out = dn; + } else { + out = ndn; + } + out->bv_len = diff + dc->rwmap->rwm_suffix_massage[i+dst].bv_len; + out->bv_val = ch_malloc( out->bv_len + 1 ); + strncpy( out->bv_val, in->bv_val, diff ); + strcpy( &out->bv_val[diff], dc->rwmap->rwm_suffix_massage[i+dst].bv_val ); #ifdef NEW_LOGGING LDAP_LOG ( BACK_LDAP, ARGS, "rwm_dn_massage: converted \"%s\" to \"%s\"\n", - in->bv_val, dn->bv_val, 0 ); + in->bv_val, out->bv_val, 0 ); #else Debug( LDAP_DEBUG_ARGS, "rwm_dn_massage:" " converted \"%s\" to \"%s\"\n", - in->bv_val, dn->bv_val, 0 ); + in->bv_val, out->bv_val, 0 ); #endif + if ( dn && ndn ) { + rc = dnNormalize( 0, NULL, NULL, dn, ndn, NULL ); + } + break; } } diff --git a/servers/slapd/overlays/rwmmap.c b/servers/slapd/overlays/rwmmap.c index 526d399128..89543c4453 100644 --- a/servers/slapd/overlays/rwmmap.c +++ b/servers/slapd/overlays/rwmmap.c @@ -163,6 +163,10 @@ rwm_map_attrnames( { int i, j; + assert( anp ); + + *anp = NULL; + if ( an == NULL ) { return LDAP_SUCCESS; } @@ -384,7 +388,7 @@ map_attr_value( fdc.ctx = "searchFilterAttrDN"; #endif - rc = rwm_dn_massage( &fdc, value, &vtmp, NULL ); + rc = rwm_dn_massage( &fdc, value, NULL, &vtmp ); switch ( rc ) { case LDAP_SUCCESS: if ( vtmp.bv_val != value->bv_val ) { @@ -413,7 +417,7 @@ map_attr_value( filter_escape_value( &vtmp, mapped_value ); if ( freeval ) { - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); } return 0; @@ -453,12 +457,12 @@ rwm_int_filter_map_rewrite( } fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(=)" ); - fstr->bv_val = malloc( fstr->bv_len + 1 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)", atmp.bv_val, vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); break; case LDAP_FILTER_GE: @@ -469,12 +473,12 @@ rwm_int_filter_map_rewrite( } fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(>=)" ); - fstr->bv_val = malloc( fstr->bv_len + 1 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)", atmp.bv_val, vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); break; case LDAP_FILTER_LE: @@ -485,12 +489,12 @@ rwm_int_filter_map_rewrite( } fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(<=)" ); - fstr->bv_val = malloc( fstr->bv_len + 1 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)", atmp.bv_val, vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); break; case LDAP_FILTER_APPROX: @@ -501,12 +505,12 @@ rwm_int_filter_map_rewrite( } fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(~=)" ); - fstr->bv_val = malloc( fstr->bv_len + 1 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)", atmp.bv_val, vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); break; case LDAP_FILTER_SUBSTRINGS: @@ -519,7 +523,7 @@ rwm_int_filter_map_rewrite( /* cannot be a DN ... */ fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" ); - fstr->bv_val = malloc( fstr->bv_len + 128 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 128 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", atmp.bv_val ); @@ -536,7 +540,7 @@ rwm_int_filter_map_rewrite( /* "(attr=" */ "%s*)", vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); } if ( f->f_sub_any != NULL ) { @@ -550,7 +554,7 @@ rwm_int_filter_map_rewrite( snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3, /* "(attr=[init]*[any*]" */ "%s*)", vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); } } @@ -566,7 +570,7 @@ rwm_int_filter_map_rewrite( /* "(attr=[init*][any*]" */ "%s)", vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); + ch_free( vtmp.bv_val ); } break; @@ -579,7 +583,7 @@ rwm_int_filter_map_rewrite( } fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" ); - fstr->bv_val = malloc( fstr->bv_len + 1 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", atmp.bv_val ); @@ -589,7 +593,7 @@ rwm_int_filter_map_rewrite( case LDAP_FILTER_OR: case LDAP_FILTER_NOT: fstr->bv_len = STRLENOF( "(%)" ); - fstr->bv_val = malloc( fstr->bv_len + 128 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 128 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)", f->f_choice == LDAP_FILTER_AND ? '&' : @@ -632,7 +636,7 @@ rwm_int_filter_map_rewrite( ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) + ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len + 1 : 0 ) + vtmp.bv_len + STRLENOF( "(:=)" ); - fstr->bv_val = malloc( fstr->bv_len + 1 ); + fstr->bv_val = ch_malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)", atmp.bv_val, @@ -640,8 +644,9 @@ rwm_int_filter_map_rewrite( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "", !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "", vtmp.bv_val ); - ber_memfree( vtmp.bv_val ); - } break; + ch_free( vtmp.bv_val ); + break; + } case SLAPD_FILTER_COMPUTED: switch ( f->f_result ) { @@ -701,7 +706,7 @@ rwm_filter_map_rewrite( case REWRITE_REGEXEC_OK: if ( !BER_BVISNULL( fstr ) ) { fstr->bv_len = strlen( fstr->bv_val ); - free( ftmp.bv_val ); + ch_free( ftmp.bv_val ); } else { *fstr = ftmp; @@ -748,7 +753,7 @@ rwm_filter_map_rewrite( * routines may be macros with args */ int -rwm_dnattr_rewrite( +rwm_referral_rewrite( Operation *op, SlapReply *rs, void *cookie, @@ -762,12 +767,12 @@ rwm_dnattr_rewrite( int i, last; dncookie dc; - struct berval dn, ndn, *pndn = NULL; + struct berval dn, ndn, *ndnp = NULL; assert( a_vals ); /* - * Rewrite the bind dn if needed + * Rewrite the dn if needed */ dc.rwmap = rwmap; #ifdef ENABLE_REWRITE @@ -781,7 +786,7 @@ rwm_dnattr_rewrite( for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ ); if ( pa_nvals != NULL ) { - pndn = &ndn; + ndnp = &ndn; if ( *pa_nvals == NULL ) { *pa_nvals = ch_malloc( last * sizeof(struct berval) ); @@ -791,9 +796,22 @@ rwm_dnattr_rewrite( last--; for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) { + struct berval olddn, oldval; int rc; + LDAPURLDesc *ludp; + + oldval = a_vals[i]; + rc = ldap_url_parse( oldval.bv_val, &ludp ); + if ( rc != LDAP_URL_SUCCESS ) { + /* leave attr untouched if massage failed */ + if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) { + ber_dupbv( &(*pa_nvals)[i], &oldval ); + } + continue; + } + ber_str2bv( ludp->lud_dn, 0, 0, &olddn ); - rc = rwm_dn_massage( &dc, &a_vals[i], &dn, pndn ); + rc = rwm_dn_massage( &dc, &olddn, &dn, ndnp ); switch ( rc ) { case LDAP_UNWILLING_TO_PERFORM: /* @@ -816,21 +834,168 @@ rwm_dnattr_rewrite( break; case LDAP_SUCCESS: - if ( !BER_BVISNULL( &dn ) && dn.bv_val != a_vals[i].bv_val ) { - ch_free( a_vals[i].bv_val ); - a_vals[i] = dn; + if ( !BER_BVISNULL( &dn ) && dn.bv_val != olddn.bv_val ) { + char *newurl; + + ludp->lud_dn = dn.bv_val; + newurl = ldap_url_desc2str( ludp ); + if ( newurl == NULL ) { + /* FIXME: leave attr untouched + * even if ldap_url_desc2str failed... */ + break; + } + + ber_str2bv( newurl, 0, 1, &a_vals[i] ); + LDAP_FREE( newurl ); + if ( pa_nvals ) { + ludp->lud_dn = ndn.bv_val; + newurl = ldap_url_desc2str( ludp ); + if ( newurl == NULL ) { + /* FIXME: leave attr untouched + * even if ldap_url_desc2str failed... */ + ch_free( a_vals[i].bv_val ); + a_vals[i] = oldval; + break; + } + if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) { ch_free( (*pa_nvals)[i].bv_val ); } - (*pa_nvals)[i] = *pndn; + ber_str2bv( newurl, 0, 1, &(*pa_nvals)[i] ); + LDAP_FREE( newurl ); } + + ch_free( oldval.bv_val ); + ludp->lud_dn = olddn.bv_val; } break; default: /* leave attr untouched if massage failed */ if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) { + ber_dupbv( &(*pa_nvals)[i], &a_vals[i] ); + } + break; + } + ldap_free_urldesc( ludp ); + } + + return 0; +} + +/* + * I don't like this much, but we need two different + * functions because different heap managers may be + * in use in back-ldap/meta to reduce the amount of + * calls to malloc routines, and some of the free() + * routines may be macros with args + */ +int +rwm_dnattr_rewrite( + Operation *op, + SlapReply *rs, + void *cookie, + BerVarray a_vals, + BerVarray *pa_nvals ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + + int i, last; + + dncookie dc; + struct berval dn, *dnp = NULL, ndn, *ndnp = NULL; + BerVarray in; + + if ( a_vals ) { + in = a_vals; + dnp = &dn; + + } else { + if ( pa_nvals == NULL || *pa_nvals == NULL ) { + return LDAP_OTHER; + } + in = *pa_nvals; + } + + /* + * Rewrite the dn if needed + */ + dc.rwmap = rwmap; +#ifdef ENABLE_REWRITE + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = (char *)cookie; +#else + dc.tofrom = ((int *)cookie)[0]; + dc.normalized = 0; +#endif + + for ( last = 0; !BER_BVISNULL( &in[last] ); last++ ); + if ( pa_nvals != NULL ) { + ndnp = &ndn; + + if ( *pa_nvals == NULL ) { + *pa_nvals = ch_malloc( last * sizeof(struct berval) ); + memset( *pa_nvals, 0, last * sizeof(struct berval) ); + } + } + last--; + + for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) { + int rc; + + rc = rwm_dn_massage( &dc, &in[i], dnp, ndnp ); + switch ( rc ) { + case LDAP_UNWILLING_TO_PERFORM: + /* + * FIXME: need to check if it may be considered + * legal to trim values when adding/modifying; + * it should be when searching (e.g. ACLs). + */ + ch_free( in[i].bv_val ); + if (last > i ) { + in[i] = in[last]; + if ( a_vals && pa_nvals ) { + (*pa_nvals)[i] = (*pa_nvals)[last]; + } + } + BER_BVZERO( &in[last] ); + if ( a_vals && pa_nvals ) { + BER_BVZERO( &(*pa_nvals)[last] ); + } + last--; + break; + + case LDAP_SUCCESS: + if ( a_vals ) { + if ( !BER_BVISNULL( &dn ) && dn.bv_val != a_vals[i].bv_val ) { + ch_free( a_vals[i].bv_val ); + a_vals[i] = dn; + + if ( pa_nvals ) { + if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) { + ch_free( (*pa_nvals)[i].bv_val ); + } + (*pa_nvals)[i] = ndn; + } + } + + } else { + assert( ndnp != NULL ); + + if ( !BER_BVISNULL( &ndn ) && ndn.bv_val != (*pa_nvals)[i].bv_val ) { + ch_free( (*pa_nvals)[i].bv_val ); + (*pa_nvals)[i] = ndn; + } + } + break; + + default: + /* leave attr untouched if massage failed */ + if ( a_vals && pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) { dnNormalize( 0, NULL, NULL, &a_vals[i], &(*pa_nvals)[i], NULL ); } break; @@ -840,6 +1005,73 @@ rwm_dnattr_rewrite( return 0; } +int +rwm_referral_result_rewrite( + dncookie *dc, + BerVarray a_vals +) +{ + int i, last; + + for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ ); + last--; + + for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) { + struct berval dn, olddn; + int rc; + LDAPURLDesc *ludp; + + rc = ldap_url_parse( a_vals[i].bv_val, &ludp ); + if ( rc != LDAP_URL_SUCCESS ) { + /* leave attr untouched if massage failed */ + continue; + } + + ber_str2bv( ludp->lud_dn, 0, 0, &olddn ); + + rc = rwm_dn_massage( dc, &olddn, &dn, NULL ); + switch ( rc ) { + case LDAP_UNWILLING_TO_PERFORM: + /* + * FIXME: need to check if it may be considered + * legal to trim values when adding/modifying; + * it should be when searching (e.g. ACLs). + */ + ch_free( &a_vals[i].bv_val ); + if ( last > i ) { + a_vals[i] = a_vals[last]; + } + BER_BVZERO( &a_vals[last] ); + last--; + break; + + default: + /* leave attr untouched if massage failed */ + if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val ) { + char *newurl; + + ludp->lud_dn = dn.bv_val; + newurl = ldap_url_desc2str( ludp ); + if ( newurl == NULL ) { + /* FIXME: leave attr untouched + * even if ldap_url_desc2str failed... */ + break; + } + + ch_free( a_vals[i].bv_val ); + ber_str2bv( newurl, 0, 1, &a_vals[i] ); + LDAP_FREE( newurl ); + ludp->lud_dn = olddn.bv_val; + } + break; + } + + ldap_free_urldesc( ludp ); + } + + return 0; +} + int rwm_dnattr_result_rewrite( dncookie *dc, @@ -863,7 +1095,7 @@ rwm_dnattr_result_rewrite( * legal to trim values when adding/modifying; * it should be when searching (e.g. ACLs). */ - LBER_FREE( &a_vals[i].bv_val ); + ch_free( &a_vals[i].bv_val ); if ( last > i ) { a_vals[i] = a_vals[last]; } @@ -874,7 +1106,7 @@ rwm_dnattr_result_rewrite( default: /* leave attr untouched if massage failed */ if ( !BER_BVISNULL( &dn ) && a_vals[i].bv_val != dn.bv_val ) { - LBER_FREE( a_vals[i].bv_val ); + ch_free( a_vals[i].bv_val ); a_vals[i] = dn; } break; diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index ca6b1ce69e..eee6982e23 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -975,6 +975,8 @@ LDAP_SLAPD_F (int) str2result LDAP_P(( char *s, int *code, char **matched, char **info )); LDAP_SLAPD_F (int) slap_map_api2result LDAP_P(( SlapReply *rs )); +LDAP_SLAPD_V( const struct berval ) slap_dummy_bv; + /* * root_dse.c */ diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 446497206c..579526c1f2 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -41,6 +41,8 @@ #include "slapi/slapi.h" #endif +const struct berval slap_dummy_bv = BER_BVNULL; + int slap_null_cb( Operation *op, SlapReply *rs ) { return 0; @@ -784,8 +786,15 @@ slap_send_search_entry( Operation *op, SlapReply *rs ) /* FIXME: maybe we could se this flag at the operation level; * however, in principle the caller of send_search_entry() may * change the attribute list at each call */ - rs->sr_opattrs = ( rs->sr_attrs == NULL ) ? SLAP_OPATTRS_NO - : ( an_find( rs->sr_attrs, &AllOper ) ? SLAP_OPATTRS : SLAP_OPATTRS_NO ); + if ( rs->sr_attrs == NULL ) { + rs->sr_attr_flags = ( SLAP_OPATTRS_NO | SLAP_USERATTRS_YES ); + + } else { + rs->sr_attr_flags |= an_find( rs->sr_attrs, &AllOper ) ? + SLAP_OPATTRS_YES : SLAP_OPATTRS_NO; + rs->sr_attr_flags |= an_find( rs->sr_attrs, &AllUser ) ? + SLAP_USERATTRS_YES : SLAP_USERATTRS_NO; + } rc = backend_operational( op, rs ); if ( rc ) { @@ -967,7 +976,7 @@ slap_send_search_entry( Operation *op, SlapReply *rs ) } else { /* specific attrs requested */ if ( is_at_operational( desc->ad_type ) ) { - if ( rs->sr_opattrs != SLAP_OPATTRS && + if ( !SLAP_OPATTRS( rs->sr_attr_flags ) && !ad_inlist( desc, rs->sr_attrs ) ) { continue; @@ -1177,7 +1186,7 @@ slap_send_search_entry( Operation *op, SlapReply *rs ) } else { /* specific attrs requested */ if( is_at_operational( desc->ad_type ) ) { - if ( rs->sr_opattrs != SLAP_OPATTRS && + if ( !SLAP_OPATTRS( rs->sr_attr_flags ) && !ad_inlist( desc, rs->sr_attrs ) ) { continue; @@ -1295,7 +1304,7 @@ slap_send_search_entry( Operation *op, SlapReply *rs ) ctx.cac_attrs = rs->sr_attrs; ctx.cac_attrsonly = op->ors_attrsonly; ctx.cac_userattrs = userattrs; - ctx.cac_opattrs = rs->sr_opattrs; + ctx.cac_opattrs = rs->sr_attr_flags; ctx.cac_acl_state = acl_state; ctx.cac_private = (void *)ber; @@ -1433,7 +1442,7 @@ error_return:; attrs_free( rs->sr_operational_attrs ); rs->sr_operational_attrs = NULL; } - rs->sr_opattrs = SLAP_OPATTRS_UNDEFINED; + rs->sr_attr_flags = SLAP_ATTRS_UNDEFINED; /* FIXME: I think rs->sr_type should be explicitly set to * REP_SEARCH here. That's what it was when we entered this diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index c42930f022..d78df940a0 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1687,10 +1687,16 @@ typedef struct rep_extended_s { typedef struct rep_search_s { Entry *r_entry; - int r_opattrs; -#define SLAP_OPATTRS_UNDEFINED (0) -#define SLAP_OPATTRS_NO (-1) -#define SLAP_OPATTRS (1) + int r_attr_flags; +#define SLAP_ATTRS_UNDEFINED (0) +#define SLAP_OPATTRS_NO (0x01) +#define SLAP_OPATTRS_YES (0x02) +#define SLAP_USERATTRS_NO (0x10) +#define SLAP_USERATTRS_YES (0x20) +#define SLAP_OPATTRS_MASK(f) ( (f) & (SLAP_OPATTRS_NO|SLAP_OPATTRS_YES) ) +#define SLAP_OPATTRS(f) ( (f) & SLAP_OPATTRS_YES ) +#define SLAP_USERATTRS_MASK(f) ( (f) & (SLAP_USERATTRS_NO|SLAP_USERATTRS_YES) ) +#define SLAP_USERATTRS(f) ( (f) & SLAP_USERATTRS_YES ) Attribute *r_operational_attrs; AttributeName *r_attrs; int r_nentries; @@ -1722,7 +1728,7 @@ typedef struct slap_rep { #define sr_attrs sr_un.sru_search.r_attrs #define sr_entry sr_un.sru_search.r_entry #define sr_operational_attrs sr_un.sru_search.r_operational_attrs -#define sr_opattrs sr_un.sru_search.r_opattrs +#define sr_attr_flags sr_un.sru_search.r_attr_flags #define sr_v2ref sr_un.sru_search.r_v2ref #define sr_nentries sr_un.sru_search.r_nentries #define sr_rspoid sr_un.sru_extended.r_rspoid diff --git a/tests/data/relay.out b/tests/data/relay.out index 3f93a013e3..3d545eaa32 100644 --- a/tests/data/relay.out +++ b/tests/data/relay.out @@ -2031,7 +2031,8 @@ homePhone: +1 313 555 8421 pager: +1 313 555 2844 facsimileTelephoneNumber: +1 313 555 9700 telephoneNumber: +1 313 555 5331 -description: Just added self in o=Beispiel,c=DE virtual naming context +description: Just added self to seeAlso in o=Beispiel,c=DE virtual naming cont + ext dn: cn=Added User,ou=Alumni Association,ou=People,o=Esempio,c=IT objectClass: OpenLDAPperson @@ -2042,5 +2043,69 @@ seeAlso: cn=All Staff,ou=Groups,o=Esempio,c=IT homePhone: +49 1234567890 drink: Beer mail: auser@mail.alumni.example.com -telephoneNumber: +1 313 555 4178 +telephoneNumber: +49 1234-567-890 +description: Just added in o=Beispiel,c=DE naming context + + +dn: ou=Referrals,dc=example,dc=com +objectClass: referral +objectClass: extensibleObject +ou: Referrals +description: Just added as ldap://localhost:9011/ou=Referrals,o=Beispiel,c=DE +description: ...and modified as ldap://localhost:9012/ou=Referrals,o=Beispiel, + c=DE +ref: ldap://localhost:9012/ou=Referrals,dc=example,dc=com??base + +dn: ou=Referrals,o=Example,c=US +objectClass: referral +objectClass: extensibleObject +ou: Referrals +description: Just added as ldap://localhost:9011/ou=Referrals,o=Beispiel,c=DE +description: ...and modified as ldap://localhost:9012/ou=Referrals,o=Beispiel, + c=DE +ref: ldap://localhost:9012/ou=Referrals,o=Example,c=US??base + +dn: ou=Referrals,o=Esempio,c=IT +objectClass: referral +objectClass: extensibleObject +ou: Referrals +description: Just added as ldap://localhost:9011/ou=Referrals,o=Beispiel,c=DE +description: ...and modified as ldap://localhost:9012/ou=Referrals,o=Beispiel, + c=DE +ref: ldap://localhost:9012/ou=Referrals,o=Esempio,c=IT??base + +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Example,c + =US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=Example,c=U + S +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=Example,c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=James A Jones 1,ou=Alumni Association,ou=People,o=Example,c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Example, + c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=Jane Q. Doe,ou=Information Technology Division,ou=People,o=Example,c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=Example,c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=John P. Doe,ou=Information Technology Division,ou=People,o=Example,c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=Example,c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US +seeAlso: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=Example,c=US + +dn: cn=Added User,ou=Alumni Association,ou=People,o=Example,c=US +seeAlso: cn=All Staff,ou=Groups,o=Example,c=US + diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index f38b534375..ec50ee8ddd 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -120,7 +120,7 @@ PORT4=9014 PORT5=9015 PORT6=9016 URI1="ldap://${LOCALHOST}:$PORT1/" -URI2="ldap://${LOCALHOST}:$PORT2" +URI2="ldap://${LOCALHOST}:$PORT2/" URI3="ldap://${LOCALHOST}:$PORT3/" URI4="ldap://${LOCALHOST}:$PORT4/" URI5="ldap://${LOCALHOST}:$PORT5/" diff --git a/tests/scripts/test030-relay b/tests/scripts/test030-relay index 807ca64956..4aef13abfa 100755 --- a/tests/scripts/test030-relay +++ b/tests/scripts/test030-relay @@ -114,7 +114,7 @@ fi BASEDN="o=Beispiel,c=DE" echo "modifying database \"$BASEDN\"..." $LDAPMODIFY -v -D "cn=Manager,$BASEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \ - >> $TESTOUT 2>&1 << EOMODS + -e manageDSAit >> $TESTOUT 2>&1 << EOMODS dn: cn=Added User,ou=Alumni Association,ou=People,$BASEDN changetype: add objectClass: OpenLDAPperson @@ -125,7 +125,8 @@ seealso: cn=All Staff,ou=Groups,$BASEDN homephone: +49 1234567890 drink: Beer mail: auser@mail.alumni.example.com -telephonenumber: +1 313 555 4178 +telephonenumber: +49 1234-567-890 +description: Just added in o=Beispiel,c=DE naming context dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN changetype: modify @@ -133,7 +134,7 @@ add: seeAlso seeAlso: cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN - add: description -description: Just added self in $BASEDN virtual naming context +description: Just added self to seeAlso in $BASEDN virtual naming context - dn: cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN @@ -150,6 +151,22 @@ newrdn: cn=Jane Q. Doe deleteoldrdn: 1 newsuperior: ou=Information Technology Division,ou=People,$BASEDN +dn: ou=Referrals,$BASEDN +changetype: add +objectclass: referral +objectclass: extensibleObject +ou: Referrals +ref: ${URI1}ou=Referrals,$BASEDN +description: Just added as ${URI1}ou=Referrals,$BASEDN + +dn: ou=Referrals,$BASEDN +changetype: modify +replace: ref +ref: ${URI2}ou=Referrals,$BASEDN +- +add: description +description: ...and modified as ${URI2}ou=Referrals,$BASEDN +- EOMODS if test $RC != 0 ; then @@ -168,6 +185,57 @@ if test $RC != 0 ; then exit $RC fi +FILTER="(objectClass=referral)" +echo "searching filter=\"$FILTER\"" +echo " attrs=\"'*' ref\"..." + +BASEDN="dc=example,dc=com" +echo " base=\"$BASEDN\"..." +$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" "$FILTER" "*" ref \ + -e manageDSAit >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "Search failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +BASEDN="o=Example,c=US" +echo " base=\"$BASEDN\"..." +$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" "$FILTER" "*" ref \ + -e manageDSAit >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "Search failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +BASEDN="o=Esempio,c=IT" +echo " base=\"$BASEDN\"..." +$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" "$FILTER" "*" ref \ + -e manageDSAit >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "Search failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +BASEDN="o=Example,c=US" +FILTER="(seeAlso=cn=all staff,ou=Groups,$BASEDN)" +echo "searching filter=\"$FILTER\"" +echo " attrs=\"seeAlso\"..." +echo " base=\"$BASEDN\"" +$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" "$FILTER" seeAlso \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "Search failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + echo "Filtering ldapsearch results..." . $LDIFFILTER < $SEARCHOUT > $SEARCHFLT echo "Filtering original ldif used to create database..." @@ -193,6 +261,7 @@ if test $RC != 0 ; then exit $RC fi +BASEDN="o=Beispiel,c=DE" echo "binding with newly changed password to database \"$BASEDN\"..." $LDAPWHOAMI -h $LOCALHOST -p $PORT1 \ -D "cn=Added User,ou=Alumni Association,ou=People,$BASEDN" \