From: Pierangelo Masarati Date: Mon, 24 Jan 2005 09:38:11 +0000 (+0000) Subject: StartTLS (ITS#3507) + chain overlay fixes and improvements X-Git-Tag: OPENLDAP_REL_ENG_2_3_BP~267 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=c6b6d2a5eca0e1ea78b6becf1ad17487d060e610;p=openldap StartTLS (ITS#3507) + chain overlay fixes and improvements --- diff --git a/servers/slapd/back-ldap/add.c b/servers/slapd/back-ldap/add.c index 1805a31b3e..eb272c7662 100644 --- a/servers/slapd/back-ldap/add.c +++ b/servers/slapd/back-ldap/add.c @@ -46,14 +46,14 @@ ldap_back_add( int isupdate; int do_retry = 1; LDAPControl **ctrls = NULL; - int rc = LDAP_SUCCESS; + rs->sr_err = LDAP_SUCCESS; + Debug( LDAP_DEBUG_ARGS, "==> ldap_back_add(\"%s\")\n", op->o_req_dn.bv_val, 0, 0 ); - lc = ldap_back_getconn( op, rs ); - if ( !lc || !ldap_back_dobind( lc, op, rs ) ) { - rc = -1; + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto cleanup; } @@ -89,20 +89,19 @@ ldap_back_add( attrs[ i ] = NULL; ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls ); - if ( rc != LDAP_SUCCESS ) { + rs->sr_err = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls ); + if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); - rc = -1; goto cleanup; } retry: rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs, ctrls, NULL, &msgid ); - rc = ldap_back_op_result( lc, op, rs, msgid, 1 ); + rs->sr_err = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; - if ( ldap_back_retry( lc, op, rs ) ) { + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto retry; } } @@ -118,8 +117,8 @@ cleanup: } Debug( LDAP_DEBUG_ARGS, "<== ldap_back_add(\"%s\"): %d\n", - op->o_req_dn.bv_val, rc, 0 ); + op->o_req_dn.bv_val, rs->sr_err, 0 ); - return rc; + return rs->sr_err; } diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 3f5b109d37..174a7039c5 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -90,12 +90,23 @@ struct ldapinfo { /* end of ID assert stuff */ ldap_pvt_thread_mutex_t conn_mutex; - int savecred; + unsigned flags; +#define LDAP_BACK_F_NONE 0x00U +#define LDAP_BACK_F_SAVECRED 0x01U +#define LDAP_BACK_F_USE_TLS 0x02U +#define LDAP_BACK_F_TLS_CRITICAL ( 0x04U | LDAP_BACK_F_USE_TLS ) Avlnode *conntree; int rwm_started; }; +typedef enum ldap_back_send_t { + LDAP_BACK_DONTSEND = 0x00, + LDAP_BACK_SENDOK = 0x01, + LDAP_BACK_SENDERR = 0x02, + LDAP_BACK_SENDRESULT = (LDAP_BACK_SENDOK|LDAP_BACK_SENDERR) +} ldap_back_send_t; + LDAP_END_DECL #include "proto-ldap.h" diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index f7446f35c9..998ce24537 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -16,7 +16,7 @@ * . */ /* ACKNOWLEDGEMENTS: - * This work was initially developed by the Howard Chu for inclusion + * This work was initially developed by Howard Chu for inclusion * in OpenLDAP Software and subsequently enhanced by Pierangelo * Masarati. */ @@ -41,6 +41,9 @@ static LDAP_REBIND_PROC ldap_back_rebind; static int ldap_back_proxy_authz_bind( struct ldapconn *lc, Operation *op, SlapReply *rs ); +static int +ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok ); + int ldap_back_bind( Operation *op, SlapReply *rs ) { @@ -50,9 +53,9 @@ ldap_back_bind( Operation *op, SlapReply *rs ) int rc = 0; ber_int_t msgid; - lc = ldap_back_getconn( op, rs ); + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); if ( !lc ) { - return( -1 ); + return rs->sr_err; } if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) { @@ -65,7 +68,7 @@ ldap_back_bind( Operation *op, SlapReply *rs ) rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val, LDAP_SASL_SIMPLE, &op->orb_cred, op->o_ctrls, NULL, &msgid ); - rc = ldap_back_op_result( lc, op, rs, msgid, 1 ); + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT ); if ( rc == LDAP_SUCCESS ) { /* If defined, proxyAuthz will be used also when @@ -84,7 +87,7 @@ ldap_back_bind( Operation *op, SlapReply *rs ) lc->lc_bound = 1; ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn ); - if ( li->savecred ) { + if ( li->flags & LDAP_BACK_F_SAVECRED ) { if ( !BER_BVISNULL( &lc->lc_cred ) ) { memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len ); @@ -219,12 +222,76 @@ ldap_back_freeconn( Operation *op, struct ldapconn *lc ) return 0; } +static int +ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) +{ + struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private; + int vers = op->o_protocol; + LDAP *ld = NULL; + + assert( lcp != NULL ); + + rs->sr_err = ldap_initialize( &ld, li->url ); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto error_return; + } + + /* Set LDAP version. This will always succeed: If the client + * bound with a particular version, then so can we. + */ + ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers ); + + /* Set LDAP version. This will always succeed: If the client + * bound with a particular version, then so can we. + */ + ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, + (const void *)&vers ); + + /* FIXME: configurable? */ + ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON ); + + if ( ( li->flags & LDAP_BACK_F_USE_TLS ) + && !ldap_is_ldaps_url( li->url ) + && ( rs->sr_err = ldap_start_tls_s( ld, NULL, NULL ) ) != LDAP_SUCCESS ) + { + /* if StartTLS is requested, only attempt it if the URL + * is not "ldaps://"; this may occur not only in case + * of misconfiguration, but also when used in the chain + * overlay, where the "uri" can be parsed out of a referral */ + if ( rs->sr_err == LDAP_SERVER_DOWN + || ( li->flags & LDAP_BACK_F_TLS_CRITICAL ) ) + { + ldap_unbind_ext_s( ld, NULL, NULL ); + goto error_return; + } + } + + if ( *lcp == NULL ) { + *lcp = (struct ldapconn *)ch_malloc( sizeof( struct ldapconn ) ); + memset( *lcp, 0, sizeof( struct ldapconn ) ); + } + (*lcp)->lc_ld = ld; + +error_return:; + if ( rs->sr_err != LDAP_SUCCESS ) { + rs->sr_err = slap_map_api2result( rs ); + if ( sendok & LDAP_BACK_SENDERR ) { + if ( rs->sr_text == NULL ) { + rs->sr_text = "ldap_initialize() failed"; + } + send_ldap_result( op, rs ); + rs->sr_text = NULL; + } + } + + return rs->sr_err; +} + struct ldapconn * -ldap_back_getconn( Operation *op, SlapReply *rs ) +ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok ) { struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private; struct ldapconn *lc, lc_curr; - LDAP *ld; int is_priv = 0; /* Searches for a ldapconn in the avl tree */ @@ -258,31 +325,12 @@ ldap_back_getconn( Operation *op, SlapReply *rs ) /* Looks like we didn't get a bind. Open a new session... */ if ( !lc ) { - int vers = op->o_protocol; - rs->sr_err = ldap_initialize( &ld, li->url ); - - if ( rs->sr_err != LDAP_SUCCESS ) { - rs->sr_err = slap_map_api2result( rs ); - if ( rs->sr_text == NULL ) { - rs->sr_text = "ldap_initialize() failed"; - } - if ( op->o_conn ) { - send_ldap_result( op, rs ); - } - rs->sr_text = NULL; - return( NULL ); + /* lc here must be NULL */ + if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) { + return NULL; } - /* Set LDAP version. This will always succeed: If the client - * bound with a particular version, then so can we. - */ - ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, - (const void *)&vers ); - /* FIXME: configurable? */ - ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON ); - lc = (struct ldapconn *)ch_malloc( sizeof( struct ldapconn ) ); lc->lc_conn = lc_curr.lc_conn; - lc->lc_ld = ld; ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn ); ldap_pvt_thread_mutex_init( &lc->lc_mutex ); @@ -320,18 +368,18 @@ ldap_back_getconn( Operation *op, SlapReply *rs ) /* Err could be -1 in case a duplicate ldapconn is inserted */ if ( rs->sr_err != 0 ) { ldap_back_conn_free( lc ); - if ( op->o_conn ) { + if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { send_ldap_error( op, rs, LDAP_OTHER, "internal server error" ); } - return( NULL ); + return NULL; } } else { Debug( LDAP_DEBUG_TRACE, "=>ldap_back_getconn: conn %p fetched\n", (void *) lc, 0, 0 ); } - return( lc ); + return lc; } /* @@ -341,12 +389,19 @@ ldap_back_getconn( Operation *op, SlapReply *rs ) * it from all the callers, and I made the function return the flag, so * it can be used to simplify the check. */ -int -ldap_back_dobind( struct ldapconn *lc, Operation *op, SlapReply *rs ) +static int +ldap_back_dobind_int( + struct ldapconn *lc, + Operation *op, + SlapReply *rs, + ldap_back_send_t sendok, + int retries ) { int rc; ber_int_t msgid; + assert( retries >= 0 ); + ldap_pvt_thread_mutex_lock( &lc->lc_mutex ); if ( !lc->lc_bound ) { /* @@ -373,12 +428,33 @@ ldap_back_dobind( struct ldapconn *lc, Operation *op, SlapReply *rs ) goto done; } +retry:; rs->sr_err = ldap_sasl_bind( lc->lc_ld, lc->lc_bound_ndn.bv_val, LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, &msgid ); - - rc = ldap_back_op_result( lc, op, rs, msgid, 0 ); + + if ( rs->sr_err == LDAP_SERVER_DOWN ) { + if ( retries > 0 ) { + ldap_unbind_ext_s( lc->lc_ld, NULL, NULL ); + lc->lc_ld = NULL; + + /* lc here must be the regular lc, reset and ready for init */ + if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) { + return 0; + } + + retries--; + goto retry; + } + + ldap_back_freeconn( op, lc ); + rs->sr_err = slap_map_api2result( rs ); + + return 0; + } + + rc = ldap_back_op_result( lc, op, rs, msgid, sendok ); if ( rc == LDAP_SUCCESS ) { lc->lc_bound = 1; } @@ -390,6 +466,12 @@ done:; return rc; } +int +ldap_back_dobind( struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) +{ + return ldap_back_dobind_int( lc, op, rs, sendok, 1 ); +} + /* * ldap_back_rebind * @@ -400,7 +482,9 @@ static int ldap_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *params ) { - struct ldapconn *lc = params; + struct ldapconn *lc = (struct ldapconn *)params; + + /* FIXME: add checks on the URL/identity? */ return ldap_sasl_bind_s( ld, lc->lc_bound_ndn.bv_val, LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL ); @@ -408,11 +492,11 @@ ldap_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, int ldap_back_op_result( - struct ldapconn *lc, - Operation *op, - SlapReply *rs, - ber_int_t msgid, - int sendok ) + struct ldapconn *lc, + Operation *op, + SlapReply *rs, + ber_int_t msgid, + ldap_back_send_t sendok ) { char *match = NULL; LDAPMessage *res = NULL; @@ -474,7 +558,10 @@ retry:; rs->sr_matched = match; } } - if ( op->o_conn && ( sendok || rs->sr_err != LDAP_SUCCESS ) ) { + if ( op->o_conn && + ( ( sendok & LDAP_BACK_SENDOK ) + || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) ) + { send_ldap_result( op, rs ); } if ( match ) { @@ -493,37 +580,20 @@ retry:; /* return true if bound, false if failed */ int -ldap_back_retry( struct ldapconn *lc, Operation *op, SlapReply *rs ) +ldap_back_retry( struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) { - struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private; - int vers = op->o_protocol; - LDAP *ld; - ldap_pvt_thread_mutex_lock( &lc->lc_mutex ); ldap_unbind_ext_s( lc->lc_ld, NULL, NULL ); + lc->lc_ld = NULL; lc->lc_bound = 0; - rs->sr_err = ldap_initialize( &ld, li->url ); - - if ( rs->sr_err != LDAP_SUCCESS ) { - rs->sr_err = slap_map_api2result( rs ); - if ( rs->sr_text == NULL ) { - rs->sr_text = "ldap_initialize() failed"; - } - if ( op->o_conn ) { - send_ldap_result( op, rs ); - } - rs->sr_text = NULL; + + /* lc here must be the regular lc, reset and ready for init */ + if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) { return 0; } - /* Set LDAP version. This will always succeed: If the client - * bound with a particular version, then so can we. - */ - ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers ); - /* FIXME: configurable? */ - ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON ); - lc->lc_ld = ld; + ldap_pvt_thread_mutex_unlock( &lc->lc_mutex ); - return ldap_back_dobind( lc, op, rs ); + return ldap_back_dobind_int( lc, op, rs, sendok, 0 ); } static int @@ -695,7 +765,7 @@ ldap_back_proxy_authz_bind( struct ldapconn *lc, Operation *op, SlapReply *rs ) goto done; } - rc = ldap_back_op_result( lc, op, rs, msgid, 0 ); + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR ); if ( rc == LDAP_SUCCESS ) { lc->lc_bound = 1; } diff --git a/servers/slapd/back-ldap/chain.c b/servers/slapd/back-ldap/chain.c index 58b6106cf0..67927c40d7 100644 --- a/servers/slapd/back-ldap/chain.c +++ b/servers/slapd/back-ldap/chain.c @@ -31,18 +31,11 @@ static BackendInfo *lback; -#if 0 -static int -ldap_chain_chk_referrals( Operation *op, SlapReply *rs ) -{ - return LDAP_SUCCESS; -} -#endif - static int ldap_chain_operational( Operation *op, SlapReply *rs ) { - /* trap entries generated by back-ldap. + /* Trap entries generated by back-ldap. + * * FIXME: we need a better way to recognize them; a cleaner * solution would be to be able to intercept the response * of be_operational(), so that we can divert only those @@ -57,8 +50,11 @@ ldap_chain_operational( Operation *op, SlapReply *rs ) return SLAP_CB_CONTINUE; } +/* + * Search specific response that strips entryDN from entries + */ static int -ldap_chain_cb_response( Operation *op, SlapReply *rs ) +ldap_chain_cb_search_response( Operation *op, SlapReply *rs ) { assert( op->o_tag == LDAP_REQ_SEARCH ); @@ -82,83 +78,159 @@ ldap_chain_cb_response( Operation *op, SlapReply *rs ) } return SLAP_CB_CONTINUE; + + } else if ( rs->sr_type == REP_RESULT ) { + /* back-ldap tried to send result */ + op->o_callback->sc_private = (void *)(1); } return 0; } +/* + * Dummy response that simply traces if back-ldap tried to send + * anything to the client + */ +static int +ldap_chain_cb_response( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_RESULT ) { + op->o_callback->sc_private = (void *)(1); + + } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) + { + /* strip the entryDN attribute, but keep returning results */ + (void)ldap_chain_cb_search_response( op, rs ); + } + + return SLAP_CB_CONTINUE; +} + +static int +ldap_chain_op( + Operation *op, + SlapReply *rs, + int ( *op_f )( Operation *op, SlapReply *rs ), + BerVarray ref ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private; + int rc; + + if ( lip->url != NULL ) { + op->o_bd->be_private = on->on_bi.bi_private; + return ( *op_f )( op, rs ); + } + + li = *lip; + op->o_bd->be_private = &li; + + /* if we parse the URI then by no means + * we can cache stuff or reuse connections, + * because in back-ldap there's no caching + * based on the URI value, which is supposed + * to be set once for all (correct?) */ + op->o_do_not_cache = 1; + + for ( ; !BER_BVISNULL( ref ); ref++ ) { + LDAPURLDesc *srv; + char *save_dn; + + /* We're setting the URI of the first referral; + * what if there are more? + +Document: draft-ietf-ldapbis-protocol-27.txt + +4.1.10. Referral + ... + If the client wishes to progress the operation, it MUST follow the + referral by contacting one of the supported services. If multiple + URIs are present, the client assumes that any supported URI may be + used to progress the operation. + + * so we actually need to follow exactly one, + * and we can assume any is fine. + */ + + /* parse reference and use + * proto://[host][:port]/ only */ + rc = ldap_url_parse_ext( ref->bv_val, &srv ); + if ( rc != LDAP_URL_SUCCESS ) { + /* try next */ + rc = LDAP_OTHER; + continue; + } + + /* remove DN essentially because later on + * ldap_initialize() will parse the URL + * as a comma-separated URL list */ + save_dn = srv->lud_dn; + srv->lud_dn = ""; + srv->lud_scope = LDAP_SCOPE_DEFAULT; + li.url = ldap_url_desc2str( srv ); + srv->lud_dn = save_dn; + ldap_free_urldesc( srv ); + + if ( li.url == NULL ) { + /* try next */ + rc = LDAP_OTHER; + continue; + } + + rc = ( *op_f )( op, rs ); + + ldap_memfree( li.url ); + li.url = NULL; + + if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) { + break; + } + } + + return rc; +} + static int ldap_chain_response( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; void *private = op->o_bd->be_private; - slap_callback *sc = op->o_callback; + slap_callback *sc = op->o_callback, + sc2 = { 0 }; int rc = 0; int cache = op->o_do_not_cache; - char *authzid = NULL; BerVarray ref; struct berval ndn = op->o_ndn; struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private; - if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) + if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) { return SLAP_CB_CONTINUE; + } + + /* + * TODO: add checks on who/when chain operations; e.g.: + * a) what identities are authorized + * b) what request DN (e.g. only chain requests rooted at ) + * c) what referral URIs + * d) what protocol scheme (e.g. only ldaps://) + * e) what ssf + */ ref = rs->sr_ref; rs->sr_ref = NULL; - op->o_callback = NULL; - - if ( lip->url == NULL ) { - /* if we parse the URI then by no means - * we can cache stuff or reuse connections, - * because in back-ldap there's no caching - * based on the URI value, which is supposed - * to be set once for all (correct?) */ - op->o_do_not_cache = 1; - - /* FIXME: we're setting the URI of the first referral; - * what if there are more? Is this something we should - * worry about? */ - li = *lip; - op->o_bd->be_private = &li; - - if ( rs->sr_type != REP_SEARCHREF ) { - LDAPURLDesc *srv; - char *save_dn; - - /* parse reference and use - * proto://[host][:port]/ only */ - rc = ldap_url_parse_ext( ref[0].bv_val, &srv ); - if ( rc != LDAP_URL_SUCCESS ) { - /* error */ - return 1; - } - - /* remove DN essentially because later on - * ldap_initialize() will parse the URL - * as a comma-separated URL list */ - save_dn = srv->lud_dn; - srv->lud_dn = ""; - srv->lud_scope = LDAP_SCOPE_DEFAULT; - li.url = ldap_url_desc2str( srv ); - srv->lud_dn = save_dn; - ldap_free_urldesc( srv ); - - if ( li.url == NULL ) { - /* error */ - return 1; - } - } - - } else { - op->o_bd->be_private = on->on_bi.bi_private; - } + /* we need this to know if back-ldap returned any result */ + sc2.sc_response = ldap_chain_cb_response; + op->o_callback = &sc2; /* Chaining can be performed by a privileged user on behalf * of normal users, using the ProxyAuthz control, by exploiting * the identity assertion feature of back-ldap; see idassert-* * directives in slapd-ldap(5). + * + * FIXME: the idassert-authcDN is one, will it be fine regardless + * of the URI we obtain from the referral? */ switch ( op->o_tag ) { @@ -166,10 +238,10 @@ ldap_chain_response( Operation *op, SlapReply *rs ) struct berval rndn = op->o_req_ndn; Connection *conn = op->o_conn; + /* FIXME: can we really get a referral for binds? */ op->o_req_ndn = slap_empty_bv; - op->o_conn = NULL; - rc = lback->bi_op_bind( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref ); op->o_req_ndn = rndn; op->o_conn = conn; } @@ -182,7 +254,7 @@ ldap_chain_response( Operation *op, SlapReply *rs ) char textbuf[ SLAP_TEXT_BUFLEN ]; size_t textlen = sizeof( textbuf ); - /* global overlay; create entry */ + /* global overlay: create entry */ /* NOTE: this is a hack to use the chain overlay * as global. I expect to be able to remove this * soon by using slap_mods2entry() earlier in @@ -197,7 +269,7 @@ ldap_chain_response( Operation *op, SlapReply *rs ) break; } } - rc = lback->bi_op_add( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_op_add, ref ); if ( cleanup_attrs ) { attrs_free( op->ora_e->e_attrs ); op->ora_e->e_attrs = NULL; @@ -205,32 +277,38 @@ ldap_chain_response( Operation *op, SlapReply *rs ) break; } case LDAP_REQ_DELETE: - rc = lback->bi_op_delete( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref ); break; case LDAP_REQ_MODRDN: - rc = lback->bi_op_modrdn( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref ); break; case LDAP_REQ_MODIFY: - rc = lback->bi_op_modify( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref ); break; case LDAP_REQ_COMPARE: - rc = lback->bi_op_compare( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref ); break; case LDAP_REQ_SEARCH: if ( rs->sr_type == REP_SEARCHREF ) { struct berval *curr = ref, odn = op->o_req_dn, ondn = op->o_req_ndn; - slap_callback sc2 = { 0 }; - int tmprc = 0; - ber_len_t refcnt = 0; - BerVarray newref = NULL; - - sc2.sc_response = ldap_chain_cb_response; - op->o_callback = &sc2; rs->sr_type = REP_SEARCH; + sc2.sc_response = ldap_chain_cb_search_response; + + li = *lip; + li.url = NULL; + op->o_bd->be_private = &li; + + /* if we parse the URI then by no means + * we can cache stuff or reuse connections, + * because in back-ldap there's no caching + * based on the URI value, which is supposed + * to be set once for all (correct?) */ + op->o_do_not_cache = 1; + /* copy the private info because we need to modify it */ for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) { LDAPURLDesc *srv; @@ -238,11 +316,11 @@ ldap_chain_response( Operation *op, SlapReply *rs ) /* parse reference and use * proto://[host][:port]/ only */ - tmprc = ldap_url_parse_ext( curr[0].bv_val, &srv ); - if ( tmprc != LDAP_URL_SUCCESS ) { - /* error */ - rc = 1; - goto end_of_searchref; + rc = ldap_url_parse_ext( curr[0].bv_val, &srv ); + if ( rc != LDAP_URL_SUCCESS ) { + /* try next */ + rs->sr_err = LDAP_OTHER; + continue; } /* remove DN essentially because later on @@ -263,15 +341,15 @@ ldap_chain_response( Operation *op, SlapReply *rs ) ldap_free_urldesc( srv ); if ( li.url == NULL ) { - /* error */ - rc = 1; - goto end_of_searchref; + /* try next */ + rs->sr_err = LDAP_OTHER; + continue; } /* FIXME: should we also copy filter and scope? * according to RFC3296, no */ - tmprc = lback->bi_op_search( op, rs ); + rc = lback->bi_op_search( op, rs ); ldap_memfree( li.url ); li.url = NULL; @@ -281,76 +359,51 @@ ldap_chain_response( Operation *op, SlapReply *rs ) op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); - if ( tmprc ) { - /* error */ - rc = 1; - goto end_of_searchref; - } - - if ( rs->sr_err != LDAP_SUCCESS ) { - /* if search was not successful, - * at least return the referral! */ - /* FIXME: assumes referrals - * are always created via - * referral_rewrite() and freed via - * ber_bvarray_free( rs->sr_ref ) */ - newref = ch_realloc( newref, sizeof( struct berval ) * (refcnt + 2) ); - ber_dupbv( &newref[ refcnt ], &curr[ 0 ] ); - refcnt++; - BER_BVZERO( &newref[ refcnt ] ); + if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) { + break; } } -end_of_searchref:; op->o_req_dn = odn; op->o_req_ndn = ondn; rs->sr_type = REP_SEARCHREF; rs->sr_entry = NULL; - /* if the error was bad, it was already returned - * by back-ldap; destroy the referrals left; - * otherwise, let the frontend return them. */ - if ( newref ) { - if ( rc == 0 ) { - rc = SLAP_CB_CONTINUE; - if ( ref != default_referral ) { - ber_bvarray_free( ref ); - } - ref = newref; - - } else { - ber_bvarray_free( newref ); - } + if ( rc != LDAP_SUCCESS ) { + /* couldn't chase any of the referrals */ + rc = SLAP_CB_CONTINUE; } } else { - rc = lback->bi_op_search( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_op_search, ref ); } break; case LDAP_REQ_EXTENDED: - rc = lback->bi_extended( op, rs ); + rc = ldap_chain_op( op, rs, lback->bi_extended, ref ); /* FIXME: ldap_back_extended() by design * doesn't send result; frontend is expected * to send it... */ if ( rc != SLAPD_ABANDON ) { send_ldap_extended( op, rs ); + rc = LDAP_SUCCESS; } break; default: rc = SLAP_CB_CONTINUE; break; } + + if ( sc2.sc_private == NULL ) { + op->o_callback = NULL; + rc = rs->sr_err = slap_map_api2result( rs ); + send_ldap_result( op, rs ); + } + op->o_do_not_cache = cache; op->o_bd->be_private = private; op->o_callback = sc; op->o_ndn = ndn; - if ( authzid ) { - op->o_tmpfree( authzid, op->o_tmpmemctx ); - } rs->sr_ref = ref; - if ( lip->url == NULL && li.url != NULL ) { - ldap_memfree( li.url ); - } return rc; } @@ -388,9 +441,9 @@ ldap_chain_db_init( BackendDB *be ) { - slap_overinst *on = (slap_overinst *) be->bd_info; - void *private = be->be_private; - int rc; + slap_overinst *on = (slap_overinst *)be->bd_info; + int rc; + BackendDB bd = *be; if ( lback == NULL ) { lback = backend_info( "ldap" ); @@ -400,10 +453,9 @@ ldap_chain_db_init( } } - be->be_private = NULL; - rc = lback->bi_db_init( be ); - on->on_bi.bi_private = be->be_private; - be->be_private = private; + bd.be_private = NULL; + rc = lback->bi_db_init( &bd ); + on->on_bi.bi_private = bd.be_private; return rc; } @@ -447,10 +499,6 @@ chain_init( void ) ldapchain.on_response = ldap_chain_response; -#if 0 - ldapchain.on_bi.bi_chk_referrals = ldap_chain_chk_referrals; -#endif - return overlay_register( &ldapchain ); } diff --git a/servers/slapd/back-ldap/compare.c b/servers/slapd/back-ldap/compare.c index ffa9f6bf77..a538e3d4b2 100644 --- a/servers/slapd/back-ldap/compare.c +++ b/servers/slapd/back-ldap/compare.c @@ -42,9 +42,8 @@ ldap_back_compare( LDAPControl **ctrls = NULL; int rc = LDAP_SUCCESS; - lc = ldap_back_getconn( op, rs ); - if (!lc || !ldap_back_dobind( lc, op, rs ) ) { - rc = -1; + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto cleanup; } @@ -52,7 +51,6 @@ ldap_back_compare( rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); - rc = -1; goto cleanup; } @@ -61,10 +59,10 @@ retry: op->orc_ava->aa_desc->ad_cname.bv_val, &op->orc_ava->aa_value, ctrls, NULL, &msgid ); - rc = ldap_back_op_result( lc, op, rs, msgid, 1 ); - if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT ); + if ( rc == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; - if ( ldap_back_retry(lc, op, rs ) ) { + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto retry; } } @@ -72,5 +70,5 @@ retry: cleanup: (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); - return rc; + return rs->sr_err; } diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index fd85eecea3..470becaa3c 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -213,6 +213,27 @@ ldap_back_db_config( li->url = ch_strdup( argv[ 1 ] ); #endif + /* start tls */ + } else if ( strcasecmp( argv[0], "start-tls" ) == 0 ) { + if ( argc != 1 ) { + fprintf( stderr, + "%s: line %d: start-tls takes no arguments\n", + fname, lineno ); + return( 1 ); + } + li->flags |= LDAP_BACK_F_TLS_CRITICAL; + + /* try start tls */ + } else if ( strcasecmp( argv[0], "try-start-tls" ) == 0 ) { + if ( argc != 1 ) { + fprintf( stderr, + "%s: line %d: try-start-tls takes no arguments\n", + fname, lineno ); + return( 1 ); + } + li->flags &= ~LDAP_BACK_F_TLS_CRITICAL; + li->flags |= LDAP_BACK_F_USE_TLS; + /* name to use for ldap_back_group */ } else if ( strcasecmp( argv[0], "acl-authcdn" ) == 0 || strcasecmp( argv[0], "binddn" ) == 0 ) @@ -272,7 +293,7 @@ ldap_back_db_config( fname, lineno ); return( 1 ); } - li->savecred = 1; + li->flags |= LDAP_BACK_F_SAVECRED; /* intercept exop_who_am_i? */ } else if ( strcasecmp( argv[0], "proxy-whoami" ) == 0 ) { @@ -360,8 +381,8 @@ ldap_back_exop_whoami( ctrls[0] = &c; op2.o_ndn = op->o_conn->c_ndn; - lc = ldap_back_getconn(&op2, rs); - if (!lc || !ldap_back_dobind( lc, op, rs )) { + lc = ldap_back_getconn(&op2, rs, LDAP_BACK_SENDERR); + if (!lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR )) { return -1; } c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; @@ -379,7 +400,7 @@ retry: &rs->sr_err); if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) { do_retry = 0; - if ( ldap_back_retry( lc, op, rs ) ) + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) goto retry; } ldap_back_freeconn( op, lc ); diff --git a/servers/slapd/back-ldap/delete.c b/servers/slapd/back-ldap/delete.c index 4b0ce6b25c..3d6575be57 100644 --- a/servers/slapd/back-ldap/delete.c +++ b/servers/slapd/back-ldap/delete.c @@ -42,9 +42,9 @@ ldap_back_delete( int do_retry = 1; int rc = LDAP_SUCCESS; - lc = ldap_back_getconn( op, rs ); + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); - if ( !lc || !ldap_back_dobind( lc, op, rs ) ) { + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { rc = -1; goto cleanup; } @@ -60,10 +60,10 @@ ldap_back_delete( retry: rs->sr_err = ldap_delete_ext( lc->lc_ld, op->o_req_ndn.bv_val, ctrls, NULL, &msgid ); - rc = ldap_back_op_result( lc, op, rs, msgid, 1 ); + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) { do_retry = 0; - if ( ldap_back_retry (lc, op, rs ) ) { + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto retry; } } diff --git a/servers/slapd/back-ldap/extended.c b/servers/slapd/back-ldap/extended.c index d4202d4c2b..8fb7e44a53 100644 --- a/servers/slapd/back-ldap/extended.c +++ b/servers/slapd/back-ldap/extended.c @@ -56,8 +56,8 @@ ldap_back_extended( * called twice; maybe we could avoid the * ldap_back_dobind() call inside each extended() * call ... */ - lc = ldap_back_getconn( op, rs ); - if ( !lc || !ldap_back_dobind( lc, op, rs ) ) { + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { return -1; } @@ -99,8 +99,8 @@ ldap_back_exop_passwd( int rc, isproxy; int do_retry = 1; - lc = ldap_back_getconn( op, rs ); - if ( !lc || !ldap_back_dobind( lc, op, rs ) ) { + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { return -1; } @@ -154,7 +154,7 @@ retry: rs->sr_err = slap_map_api2result( rs ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; - if ( ldap_back_retry(lc, op, rs ) ) { + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto retry; } } diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index b00c579d36..84f47becbd 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -144,10 +144,10 @@ ldap_back_db_open( BackendDB *be ) /* FIXME: disabled because namingContexts doesn't have * a matching rule, and using an MRA filter doesn't work * because the normalized assertion is compared to the - * non-normalized value, which in general differ. - * See ITS#3406 */ + * non-normalized value, which in general differs from + * the normalized one. See ITS#3406 */ struct berval filter, - base = BER_BVC( "cn=Databases,cn=Monitor" ); + base = BER_BVC( "cn=Databases," SLAPD_MONITOR ); struct berval vals[ 2 ]; Attribute a = { 0 }; diff --git a/servers/slapd/back-ldap/modify.c b/servers/slapd/back-ldap/modify.c index cc551243a1..0936bb4e0f 100644 --- a/servers/slapd/back-ldap/modify.c +++ b/servers/slapd/back-ldap/modify.c @@ -46,8 +46,8 @@ ldap_back_modify( int do_retry = 1; LDAPControl **ctrls = NULL; - lc = ldap_back_getconn( op, rs ); - if ( !lc || !ldap_back_dobind( lc, op, rs ) ) { + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { return -1; } @@ -106,10 +106,10 @@ ldap_back_modify( retry: rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_ndn.bv_val, modv, ctrls, NULL, &msgid ); - rc = ldap_back_op_result( lc, op, rs, msgid, 1 ); + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; - if ( ldap_back_retry(lc, op, rs ) ) { + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto retry; } } diff --git a/servers/slapd/back-ldap/modrdn.c b/servers/slapd/back-ldap/modrdn.c index 92cce0a749..22554b2430 100644 --- a/servers/slapd/back-ldap/modrdn.c +++ b/servers/slapd/back-ldap/modrdn.c @@ -43,8 +43,8 @@ ldap_back_modrdn( int rc = LDAP_SUCCESS; char *newSup = NULL; - lc = ldap_back_getconn( op, rs ); - if ( !lc || !ldap_back_dobind( lc, op, rs ) ) { + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { return( -1 ); } @@ -67,10 +67,10 @@ retry: rs->sr_err = ldap_rename( lc->lc_ld, op->o_req_ndn.bv_val, op->orr_newrdn.bv_val, newSup, op->orr_deleteoldrdn, ctrls, NULL, &msgid ); - rc = ldap_back_op_result( lc, op, rs, msgid, 1 ); + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) { do_retry = 0; - if ( ldap_back_retry( lc, op, rs ) ) { + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto retry; } } diff --git a/servers/slapd/back-ldap/proto-ldap.h b/servers/slapd/back-ldap/proto-ldap.h index eadc7d3949..8c85f507f4 100644 --- a/servers/slapd/back-ldap/proto-ldap.h +++ b/servers/slapd/back-ldap/proto-ldap.h @@ -49,12 +49,12 @@ extern BI_connection_destroy ldap_back_conn_destroy; extern BI_entry_get_rw ldap_back_entry_get; int ldap_back_freeconn( Operation *op, struct ldapconn *lc ); -struct ldapconn *ldap_back_getconn(struct slap_op *op, struct slap_rep *rs); -int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs); -int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs); +struct ldapconn *ldap_back_getconn(struct slap_op *op, struct slap_rep *rs, ldap_back_send_t sendok); +int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok); +int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok); int ldap_back_map_result(SlapReply *rs); int ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs, - ber_int_t msgid, int sendok); + ber_int_t msgid, ldap_back_send_t sendok); int back_ldap_LTX_init_module(int argc, char *argv[]); extern int ldap_back_conn_cmp( const void *c1, const void *c2); diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index bf78dec637..b42352614f 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -60,17 +60,17 @@ ldap_back_search( int do_retry = 1; LDAPControl **ctrls = NULL; - lc = ldap_back_getconn( op, rs ); + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); if ( !lc ) { - return -1; + return rs->sr_err; } /* * FIXME: in case of values return filter, we might want * to map attrs and maybe rewrite value */ - if ( !ldap_back_dobind( lc, op, rs ) ) { - return -1; + if ( !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { + return rs->sr_err; } /* should we check return values? */ @@ -120,7 +120,7 @@ retry: if ( rs->sr_err != LDAP_SUCCESS ) { fail:; - rc = ldap_back_op_result( lc, op, rs, msgid, 0 ); + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR ); if ( freeconn ) { ldap_back_freeconn( op, lc ); lc = NULL; @@ -249,7 +249,7 @@ fail:; if ( rc == -1 ) { if ( do_retry ) { do_retry = 0; - if ( ldap_back_retry( lc, op, rs ) ) { + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { goto retry; } } @@ -500,7 +500,6 @@ ldap_back_entry_get( *e = NULL; char *gattr[3]; char *filter = NULL; - Connection *oconn; SlapReply rs; int do_retry = 1; LDAPControl **ctrls = NULL; @@ -508,16 +507,12 @@ ldap_back_entry_get( /* Tell getconn this is a privileged op */ do_not_cache = op->o_do_not_cache; op->o_do_not_cache = 1; - lc = ldap_back_getconn( op, &rs ); - oconn = op->o_conn; - op->o_conn = NULL; - if ( !lc || !ldap_back_dobind( lc, op, &rs ) ) { + lc = ldap_back_getconn( op, &rs, LDAP_BACK_DONTSEND ); + if ( !lc || !ldap_back_dobind( lc, op, &rs, LDAP_BACK_DONTSEND ) ) { op->o_do_not_cache = do_not_cache; - op->o_conn = oconn; - return 1; + return rs.sr_err; } op->o_do_not_cache = do_not_cache; - op->o_conn = oconn; if ( at ) { if ( oc && at != slap_schema.si_ad_objectClass ) { @@ -555,7 +550,7 @@ retry: if ( rc != LDAP_SUCCESS ) { if ( rc == LDAP_SERVER_DOWN && do_retry ) { do_retry = 0; - if ( ldap_back_retry( lc, op, &rs ) ) { + if ( ldap_back_retry( lc, op, &rs, LDAP_BACK_DONTSEND ) ) { goto retry; } } diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 50dd8e584b..3ead454bb4 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -85,15 +85,6 @@ typedef struct dncookie { #define META_BIND_NRETRIES 3 #define META_BIND_TIMEOUT 1000 -int ldap_back_freeconn( Operation *op, struct ldapconn *lc ); -struct ldapconn *ldap_back_getconn(struct slap_op *op, struct slap_rep *rs); -int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs); -int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs); -int ldap_back_map_result(SlapReply *rs); -int ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs, - ber_int_t msgid, int sendok); -int back_ldap_LTX_init_module(int argc, char *argv[]); - int ldap_back_dn_massage(dncookie *dc, struct berval *dn, struct berval *res); diff --git a/tests/data/chain.out b/tests/data/chain.out index 3d53473989..985f5dd4df 100644 --- a/tests/data/chain.out +++ b/tests/data/chain.out @@ -386,6 +386,10 @@ pager: +1 313 555 7671 facsimileTelephoneNumber: +1 313 555 7762 telephoneNumber: +1 313 555 4177 +dn: ou=Other,dc=example,dc=com +objectClass: organizationalUnit +ou: Other + dn: ou=People,dc=example,dc=com objectClass: organizationalUnit objectClass: extensibleObject diff --git a/tests/data/chainmod.out b/tests/data/chainmod.out index a15e26f528..67970afc2f 100644 --- a/tests/data/chainmod.out +++ b/tests/data/chainmod.out @@ -365,6 +365,10 @@ pager: +1 313 555 7671 facsimileTelephoneNumber: +1 313 555 7762 telephoneNumber: +1 313 555 4177 +dn: ou=Other,dc=example,dc=com +objectClass: organizationalUnit +ou: Other + dn: ou=People,dc=example,dc=com objectClass: organizationalUnit objectClass: extensibleObject diff --git a/tests/data/chainref.out b/tests/data/chainref.out new file mode 100644 index 0000000000..bec32503cb --- /dev/null +++ b/tests/data/chainref.out @@ -0,0 +1,4 @@ +dn: ou=Other,dc=example,dc=com +objectClass: organizationalUnit +ou: Other + diff --git a/tests/data/test-chain1.ldif b/tests/data/test-chain1.ldif index 7f419fd20c..76e22f7629 100644 --- a/tests/data/test-chain1.ldif +++ b/tests/data/test-chain1.ldif @@ -29,6 +29,14 @@ objectclass: extensibleobject ou: Groups ref: @URI2@ou=Groups,dc=example,dc=com +dn: ou=Other,dc=example,dc=com +objectclass: referral +objectclass: extensibleobject +ou: Other +# invalid URI first to test failover capabilities (search only) +ref: @URI3@ou=Other,dc=example,dc=com +ref: @URI2@ou=Other,dc=example,dc=com + dn: ou=Alumni Association,ou=People,dc=example,dc=com objectclass: organizationalUnit ou: Alumni Association diff --git a/tests/data/test-chain2.ldif b/tests/data/test-chain2.ldif index fe0cd3e920..e1fb680216 100644 --- a/tests/data/test-chain2.ldif +++ b/tests/data/test-chain2.ldif @@ -81,3 +81,8 @@ cn: Dir Man sn: Manager description: Manager of the directory userpassword:: c2VjcmV0 + +dn: ou=Other,dc=example,dc=com +objectclass: organizationalUnit +ou: Other + diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index c083e666d8..bb6d4011d4 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -235,6 +235,7 @@ LDAPGLUEOUT=$DATADIR/ldapglue.out LDAPGLUEANONYMOUSOUT=$DATADIR/ldapglueanonymous.out RELAYOUT=$DATADIR/relay.out CHAINOUT=$DATADIR/chain.out +CHAINREFOUT=$DATADIR/chainref.out CHAINMODOUT=$DATADIR/chainmod.out SQLREAD=$DATADIR/sql-read.out SQLWRITE=$DATADIR/sql-write.out diff --git a/tests/scripts/test032-chain b/tests/scripts/test032-chain index de27ec0fce..7bf073a3fd 100755 --- a/tests/scripts/test032-chain +++ b/tests/scripts/test032-chain @@ -110,6 +110,31 @@ for P in $PORT1 $PORT2 ; do test $KILLSERVERS != no && kill -HUP $KILLPIDS exit 1 fi + + echo "Reading the referral entry "ou=Other,$BASEDN" as anonymous on port $P..." + $LDAPSEARCH -h $LOCALHOST -p $P -b "ou=Other,$BASEDN" -S "" \ + > $SEARCHOUT 2>&1 + + RC=$? + if test $RC != 0 ; then + echo "ldapsearch 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..." + . $LDIFFILTER < $CHAINREFOUT > $LDIFFLT + echo "Comparing filter output..." + $CMP $SEARCHFLT $LDIFFLT > $CMPOUT + + if test $? != 0 ; then + echo "comparison failed - chained search didn't succeed" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + done #