X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-meta%2Fbind.c;h=acfc69577cecd577ba97c1279eae8e2f31d6dccb;hb=caf751fbb20fbccf535b900df1dabef0f40e0222;hp=d2d9cb02d6e40163752ff1eaeb46c3284f2dc41c;hpb=6416d83372aa272a72414cd985fab731cde556c7;p=openldap diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index d2d9cb02d6..acfc69577c 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1999-2006 The OpenLDAP Foundation. + * Copyright 1999-2012 The OpenLDAP Foundation. * Portions Copyright 2001-2003 Pierangelo Masarati. * Portions Copyright 1999-2003 Howard Chu. * All rights reserved. @@ -42,7 +42,8 @@ meta_back_proxy_authz_bind( int candidate, Operation *op, SlapReply *rs, - ldap_back_send_t sendok ); + ldap_back_send_t sendok, + int dolock ); static int meta_back_single_bind( @@ -62,7 +63,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) gotit = 0, isroot = 0; - SlapReply *candidates = meta_back_candidates_get( op ); + SlapReply *candidates; rs->sr_err = LDAP_SUCCESS; @@ -70,24 +71,22 @@ meta_back_bind( Operation *op, SlapReply *rs ) op->o_log_prefix, op->o_req_dn.bv_val, 0 ); /* the test on the bind method should be superfluous */ - if ( op->orb_method == LDAP_AUTH_SIMPLE - && be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) - { - if ( !be_isroot_pw( op ) ) { - rs->sr_err = LDAP_INVALID_CREDENTIALS; - rs->sr_text = NULL; - send_ldap_result( op, rs ); - return rs->sr_err; - } - + switch ( be_rootdn_bind( op, rs ) ) { + case LDAP_SUCCESS: if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) { - rs->sr_err = LDAP_SUCCESS; - rs->sr_text = NULL; /* frontend will return success */ return rs->sr_err; } isroot = 1; + /* fallthru */ + + case SLAP_CB_CONTINUE: + break; + + default: + /* be_rootdn_bind() sent result */ + return rs->sr_err; } /* we need meta_back_getconn() not send result even on error, @@ -122,6 +121,8 @@ meta_back_bind( Operation *op, SlapReply *rs ) return rs->sr_err; } + candidates = meta_back_candidates_get( op ); + /* * Each target is scanned ... */ @@ -143,7 +144,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) rc = LDAP_SUCCESS; gotit = 1; - } else if ( isroot == 0 ) { + } else if ( !isroot ) { /* * A bind operation is expected to have * ONE CANDIDATE ONLY! @@ -166,9 +167,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) BER_BVZERO( &msc->msc_bound_ndn ); } - if ( LDAP_BACK_SAVECRED( mi ) && - !BER_BVISNULL( &msc->msc_cred ) ) - { + if ( !BER_BVISNULL( &msc->msc_cred ) ) { /* destroy sensitive data */ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); @@ -180,7 +179,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) } - (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND ); + (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 ); lerr = rs->sr_err; } else { @@ -189,6 +188,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) if ( lerr != LDAP_SUCCESS ) { rc = rs->sr_err = lerr; + /* FIXME: in some cases (e.g. unavailable) * do not assume it's not candidate; rather * mark this as an error to be eventually @@ -202,37 +202,30 @@ meta_back_bind( Operation *op, SlapReply *rs ) if ( rc == LDAP_SUCCESS ) { if ( isroot ) { mc->mc_authz_target = META_BOUND_ALL; - ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ) ); } - if ( !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) { - metaconn_t *tmpmc; + if ( !LDAP_BACK_PCONN_ISPRIV( mc ) + && !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) + { int lerr; /* wait for all other ops to release the connection */ -retry_lock:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); - if ( mc->mc_refcnt > 1 ) { - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - ldap_pvt_thread_yield(); - goto retry_lock; - } - assert( mc->mc_refcnt == 1 ); #if META_BACK_PRINT_CONNTREE > 0 - meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_bind" ); + meta_back_print_conntree( mi, ">>> meta_back_bind" ); #endif /* META_BACK_PRINT_CONNTREE */ - tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, - meta_back_conndn_cmp ); - assert( tmpmc == mc ); /* delete all cached connections with the current connection */ if ( LDAP_BACK_SINGLECONN( mi ) ) { + metaconn_t *tmpmc; + while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL ) { + assert( !LDAP_BACK_PCONN_ISPRIV( mc ) ); Debug( LDAP_DEBUG_TRACE, - "=>meta_back_bind: destroying conn %ld (refcnt=%u)\n", - LDAP_BACK_PCONN_ID( mc ), mc->mc_refcnt, 0 ); + "=>meta_back_bind: destroying conn %lu (refcnt=%u)\n", + mc->mc_conn->c_connid, mc->mc_refcnt, 0 ); if ( tmpmc->mc_refcnt != 0 ) { /* taint it */ @@ -250,28 +243,32 @@ retry_lock:; } ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); - if ( isroot ) { - mc->mc_conn = LDAP_BACK_PCONN_SET( op ); - } lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conndn_cmp, meta_back_conndn_dup ); #if META_BACK_PRINT_CONNTREE > 0 - meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_bind" ); + meta_back_print_conntree( mi, "<<< meta_back_bind" ); #endif /* META_BACK_PRINT_CONNTREE */ - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - if ( lerr == -1 ) { - meta_clear_candidates( op, mc ); + if ( lerr == 0 ) { +#if 0 + /* NOTE: a connection cannot be privileged + * and be in the avl tree at the same time + */ + if ( isroot ) { + LDAP_BACK_CONN_ISPRIV_SET( mc ); + LDAP_BACK_PCONN_SET( mc, op ); + } +#endif + LDAP_BACK_CONN_CACHED_SET( mc ); - /* we can do this because mc_refcnt == 1 */ - mc->mc_refcnt = 0; - meta_back_conn_free( mc ); - mc = NULL; + } else { + LDAP_BACK_CONN_CACHED_CLEAR( mc ); } + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } } if ( mc != NULL ) { - meta_back_release_conn( op, mc ); + meta_back_release_conn( mi, mc ); } /* @@ -309,7 +306,8 @@ meta_back_bind_op_result( metaconn_t *mc, int candidate, int msgid, - ldap_back_send_t sendok ) + ldap_back_send_t sendok, + int dolock ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; @@ -324,6 +322,9 @@ meta_back_bind_op_result( ">>> %s meta_back_bind_op_result[%d]\n", op->o_log_prefix, candidate, 0 ); + /* make sure this is clean */ + assert( rs->sr_ctrls == NULL ); + if ( rs->sr_err == LDAP_SUCCESS ) { time_t stoptime = (time_t)(-1), timeout; @@ -371,12 +372,6 @@ retry:; rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case 0: -#if 0 - Debug( LDAP_DEBUG_ANY, - "%s meta_back_bind_op_result[%d]: ldap_result=0 nretries=%d.\n", - op->o_log_prefix, candidate, nretries ); -#endif - if ( nretries != META_RETRY_NEVER || ( timeout && slap_get_time() <= stoptime ) ) { @@ -391,18 +386,27 @@ retry:; /* don't let anyone else use this handler, * because there's a pending bind that will not * be acknowledged */ - ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); - ldap_unbind_ext( msc->msc_ld, NULL, NULL ); - msc->msc_ld = NULL; - LDAP_BACK_CONN_BINDING_CLEAR( msc ); - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + if ( dolock) { + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + } + assert( LDAP_BACK_CONN_BINDING( msc ) ); + +#ifdef DEBUG_205 + Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n", + op->o_log_prefix, candidate, (void *)msc->msc_ld ); +#endif /* DEBUG_205 */ + + meta_clear_one_candidate( op, mc, candidate ); + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + } rs->sr_err = timeout_err; rs->sr_text = timeout_text; break; case -1: - ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, + ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); snprintf( buf, sizeof( buf ), @@ -425,6 +429,7 @@ retry:; if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } + rs->sr_err = slap_map_api2result( rs ); break; } } @@ -456,13 +461,16 @@ meta_back_single_bind( metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int msgid; dncookie dc; + struct berval save_o_dn; + int save_o_do_not_cache; + LDAPControl **ctrls = NULL; if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ch_free( msc->msc_bound_ndn.bv_val ); BER_BVZERO( &msc->msc_bound_ndn ); } - if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &msc->msc_cred ) ) { + if ( !BER_BVISNULL( &msc->msc_cred ) ) { /* destroy sensitive data */ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); ch_free( msc->msc_cred.bv_val ); @@ -483,15 +491,38 @@ meta_back_single_bind( return rs->sr_err; } + /* don't add proxyAuthz; set the bindDN */ + save_o_dn = op->o_dn; + save_o_do_not_cache = op->o_do_not_cache; + op->o_do_not_cache = 1; + op->o_dn = op->o_req_dn; + + ctrls = op->o_ctrls; + rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls ); + op->o_dn = save_o_dn; + op->o_do_not_cache = save_o_do_not_cache; + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + /* FIXME: this fixes the bind problem right now; we need * to use the asynchronous version to get the "matched" * and more in case of failure ... */ /* FIXME: should we check if at least some of the op->o_ctrls * can/should be passed? */ - rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val, + for (;;) { + rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val, LDAP_SASL_SIMPLE, &op->orb_cred, - op->o_ctrls, NULL, &msgid ); - meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND ); + ctrls, NULL, &msgid ); + if ( rs->sr_err != LDAP_X_CONNECTING ) { + break; + } + ldap_pvt_thread_yield(); + } + + mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); + + meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 ); if ( rs->sr_err != LDAP_SUCCESS ) { goto return_results; } @@ -502,7 +533,7 @@ meta_back_single_bind( * bind with the configured identity assertion */ /* NOTE: use with care */ if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) { - meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR ); + meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 ); if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) { goto return_results; } @@ -513,7 +544,11 @@ meta_back_single_bind( LDAP_BACK_CONN_ISBOUND_SET( msc ); mc->mc_authz_target = candidate; - if ( LDAP_BACK_SAVECRED( mi ) ) { + if ( META_BACK_TGT_SAVECRED( mt ) ) { + if ( !BER_BVISNULL( &msc->msc_cred ) ) { + memset( msc->msc_cred.bv_val, 0, + msc->msc_cred.bv_len ); + } ber_bvreplace( &msc->msc_cred, &op->orb_cred ); ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc ); } @@ -555,8 +590,6 @@ meta_back_single_dobind( metatarget_t *mt = mi->mi_targets[ candidate ]; metaconn_t *mc = *mcp; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - int rc; - static struct berval cred = BER_BVC( "" ); int msgid; assert( !LDAP_BACK_CONN_ISBOUND( msc ) ); @@ -566,46 +599,72 @@ meta_back_single_dobind( !op->o_do_not_cache && ( BER_BVISNULL( &msc->msc_bound_ndn ) || BER_BVISEMPTY( &msc->msc_bound_ndn ) || - ( LDAP_BACK_CONN_ISPRIV( msc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || + ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) { - (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok ); - rc = rs->sr_err; - goto done; - } + (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock ); - /* FIXME: should we check if at least some of the op->o_ctrls - * can/should be passed? */ - rs->sr_err = ldap_sasl_bind( msc->msc_ld, "", LDAP_SASL_SIMPLE, &cred, - NULL, NULL, &msgid ); - rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok ); + } else { + char *binddn = ""; + struct berval cred = BER_BVC( "" ); -done:; - rs->sr_err = rc; - if ( rc != LDAP_SUCCESS ) { + /* use credentials if available */ + if ( !BER_BVISNULL( &msc->msc_bound_ndn ) + && !BER_BVISNULL( &msc->msc_cred ) ) + { + binddn = msc->msc_bound_ndn.bv_val; + cred = msc->msc_cred; + } + + /* FIXME: should we check if at least some of the op->o_ctrls + * can/should be passed? */ + for (;;) { + rs->sr_err = ldap_sasl_bind( msc->msc_ld, + binddn, LDAP_SASL_SIMPLE, &cred, + NULL, NULL, &msgid ); + if ( rs->sr_err != LDAP_X_CONNECTING ) { + break; + } + ldap_pvt_thread_yield(); + } + + rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock ); + + /* if bind succeeded, but anonymous, clear msc_bound_ndn */ + if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) { + if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { + ber_memfree( msc->msc_bound_ndn.bv_val ); + BER_BVZERO( &msc->msc_bound_ndn ); + } + + if ( !BER_BVISNULL( &msc->msc_cred ) ) { + memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); + ber_memfree( msc->msc_cred.bv_val ); + BER_BVZERO( &msc->msc_cred ); + } + } + } + + if ( rs->sr_err != LDAP_SUCCESS ) { if ( dolock ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } - LDAP_BACK_CONN_BINDING_CLEAR( msc ); + LDAP_BACK_CONN_BINDING_CLEAR( msc ); if ( META_BACK_ONERR_STOP( mi ) ) { - LDAP_BACK_CONN_TAINTED_SET( mc ); - meta_back_release_conn_lock( op, mc, 0 ); + LDAP_BACK_CONN_TAINTED_SET( mc ); + meta_back_release_conn_lock( mi, mc, 0 ); *mcp = NULL; } if ( dolock ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } - - if ( META_BACK_ONERR_STOP( mi ) && ( sendok & LDAP_BACK_SENDERR ) ) { - send_ldap_result( op, rs ); - } } if ( META_BACK_TGT_QUARANTINE( mt ) ) { meta_back_quarantine( op, rs, candidate ); } - return rc; + return rs->sr_err; } /* @@ -624,17 +683,21 @@ meta_back_dobind( i, isroot = 0; - SlapReply *candidates = meta_back_candidates_get( op ); + SlapReply *candidates; if ( be_isroot( op ) ) { isroot = 1; } - Debug( LDAP_DEBUG_TRACE, - "%s meta_back_dobind: conn=%ld%s\n", - op->o_log_prefix, - LDAP_BACK_PCONN_ID( mc ), - isroot ? " (isroot)" : "" ); + if ( LogTest( LDAP_DEBUG_TRACE ) ) { + char buf[STRLENOF("4294967295U") + 1] = { 0 }; + mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); + + Debug( LDAP_DEBUG_TRACE, + "%s meta_back_dobind: conn=%s%s\n", + op->o_log_prefix, buf, + isroot ? " (isroot)" : "" ); + } /* * all the targets are bound as pseudoroot @@ -644,6 +707,8 @@ meta_back_dobind( goto done; } + candidates = meta_back_candidates_get( op ); + for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; metasingleconn_t *msc = &mc->mc_conns[ i ]; @@ -672,7 +737,8 @@ retry_binding:; ++bound; continue; - } else if ( LDAP_BACK_CONN_BINDING( msc ) ) { + } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) + { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_yield(); goto retry_binding; @@ -699,7 +765,7 @@ retry_binding:; if ( rc == LDAP_UNAVAILABLE ) { - /* FIXME: meta_back_retry() already calls + /* FIXME: meta_back_retry() already re-calls * meta_back_single_dobind() */ if ( meta_back_retry( op, rs, &mc, i, sendok ) ) { goto retry_ok; @@ -708,6 +774,7 @@ retry_binding:; if ( mc != NULL ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); + meta_back_release_conn_lock( mi, mc, 0 ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } @@ -762,12 +829,17 @@ retry_ok:; } done:; - Debug( LDAP_DEBUG_TRACE, - "%s meta_back_dobind: conn=%ld bound=%d\n", - op->o_log_prefix, LDAP_BACK_PCONN_ID( mc ), bound ); + if ( LogTest( LDAP_DEBUG_TRACE ) ) { + char buf[STRLENOF("4294967295U") + 1] = { 0 }; + mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); + + Debug( LDAP_DEBUG_TRACE, + "%s meta_back_dobind: conn=%s bound=%d\n", + op->o_log_prefix, buf, bound ); + } if ( bound == 0 ) { - meta_back_release_conn( op, mc ); + meta_back_release_conn( mi, mc ); send_err:; if ( sendok & LDAP_BACK_SENDERR ) { @@ -865,7 +937,7 @@ meta_back_cancel( rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL ); } else if ( META_BACK_TGT_IGNORE( mt ) ) { - rc = ldap_int_discard( msc->msc_ld, msgid ); + rc = ldap_pvt_discard( msc->msc_ld, msgid ); } else if ( META_BACK_TGT_CANCEL( mt ) ) { rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL ); @@ -919,9 +991,7 @@ meta_back_op_result( metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; -#define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE) - - if ( ERR_OK( rs->sr_err ) ) { + if ( LDAP_ERR_OK( rs->sr_err ) ) { int rc; struct timeval tv; LDAPMessage *res = NULL; @@ -1000,22 +1070,50 @@ retry:; rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, &matched, &text, &refs, &ctrls, 1 ); res = NULL; - rs->sr_text = text; - if ( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_SUCCESS ) { + rs->sr_text = text; + } else { rs->sr_err = rc; } - if ( refs != NULL ) { - int i; + rs->sr_err = slap_map_api2result( rs ); + + /* RFC 4511: referrals can only appear + * if result code is LDAP_REFERRAL */ + if ( refs != NULL + && refs[ 0 ] != NULL + && refs[ 0 ][ 0 ] != '\0' ) + { + if ( rs->sr_err != LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_op_result[%d]: " + "got referrals with err=%d\n", + op->o_log_prefix, + candidate, rs->sr_err ); + + } else { + int i; - for ( i = 0; refs[ i ] != NULL; i++ ) - /* count */ ; - rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), - op->o_tmpmemctx ); - for ( i = 0; refs[ i ] != NULL; i++ ) { - ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + for ( i = 0; refs[ i ] != NULL; i++ ) + /* count */ ; + rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), + op->o_tmpmemctx ); + for ( i = 0; refs[ i ] != NULL; i++ ) { + ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + } + BER_BVZERO( &rs->sr_ref[ i ] ); } - BER_BVZERO( &rs->sr_ref[ i ] ); + + } else if ( rs->sr_err == LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_op_result[%d]: " + "got err=%d with null " + "or empty referrals\n", + op->o_log_prefix, + candidate, rs->sr_err ); + + rs->sr_err = LDAP_NO_SUCH_OBJECT; } + if ( ctrls != NULL ) { rs->sr_ctrls = ctrls; } @@ -1027,7 +1125,7 @@ retry:; /* if the error in the reply structure is not * LDAP_SUCCESS, try to map it from client * to server error */ - if ( !ERR_OK( rs->sr_err ) ) { + if ( !LDAP_ERR_OK( rs->sr_err ) ) { rs->sr_err = slap_map_api2result( rs ); /* internal ops ( op->o_conn == NULL ) @@ -1053,6 +1151,10 @@ retry:; char *xtext = NULL; char *xmatched = NULL; + if ( msc->msc_ld == NULL ) { + continue; + } + rs->sr_err = LDAP_SUCCESS; ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err ); @@ -1146,9 +1248,17 @@ retry:; rs->sr_matched = matched; } - if ( op->o_conn && - ( ( sendok & LDAP_BACK_SENDOK ) - || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) ) + if ( rs->sr_err == LDAP_UNAVAILABLE ) { + if ( !( sendok & LDAP_BACK_RETRYING ) ) { + if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { + if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed"; + send_ldap_result( op, rs ); + } + } + + } else if ( op->o_conn && + ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) ) + || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) ) { send_ldap_result( op, rs ); } @@ -1159,9 +1269,11 @@ retry:; ldap_memfree( text ); } if ( rs->sr_ref ) { - assert( refs != NULL ); - ber_memvfree( (void **)refs ); op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); + rs->sr_ref = NULL; + } + if ( refs ) { + ber_memvfree( (void **)refs ); } if ( ctrls ) { assert( rs->sr_ctrls != NULL ); @@ -1173,7 +1285,7 @@ retry:; rs->sr_ref = save_ref; rs->sr_ctrls = save_ctrls; - return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); + return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); } /* @@ -1228,6 +1340,7 @@ meta_back_proxy_authz_cred( } else { ndn = op->o_ndn; } + rs->sr_err = LDAP_SUCCESS; /* * FIXME: we need to let clients use proxyAuthz @@ -1266,22 +1379,24 @@ meta_back_proxy_authz_cred( default: /* NOTE: rootdn can always idassert */ - if ( BER_BVISNULL( &ndn ) && mt->mt_idassert_authz == NULL ) { + if ( BER_BVISNULL( &ndn ) + && mt->mt_idassert_authz == NULL + && !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) + { if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { rs->sr_err = LDAP_INAPPROPRIATE_AUTH; if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); + goto done; - } else { - rs->sr_err = LDAP_SUCCESS; - *binddn = slap_empty_bv; - *bindcred = slap_empty_bv; - break; } - goto done; + rs->sr_err = LDAP_SUCCESS; + *binddn = slap_empty_bv; + *bindcred = slap_empty_bv; + break; } else if ( mt->mt_idassert_authz && !be_isroot( op ) ) { struct berval authcDN; @@ -1300,15 +1415,13 @@ meta_back_proxy_authz_cred( send_ldap_result( op, rs ); } LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); - - } else { - rs->sr_err = LDAP_SUCCESS; - *binddn = slap_empty_bv; - *bindcred = slap_empty_bv; - break; + goto done; } - goto done; + rs->sr_err = LDAP_SUCCESS; + *binddn = slap_empty_bv; + *bindcred = slap_empty_bv; + break; } } @@ -1378,6 +1491,14 @@ meta_back_proxy_authz_cred( mt->mt_idassert_authcID.bv_val, mt->mt_idassert_passwd.bv_val, authzID.bv_val ); + if ( defaults == NULL ) { + rs->sr_err = LDAP_OTHER; + LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + } + goto done; + } rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val, mt->mt_idassert_sasl_mech.bv_val, NULL, NULL, @@ -1425,11 +1546,22 @@ meta_back_proxy_authz_cred( } done:; + + if ( !BER_BVISEMPTY( binddn ) ) { + LDAP_BACK_CONN_ISIDASSERT_SET( msc ); + } + return rs->sr_err; } static int -meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) +meta_back_proxy_authz_bind( + metaconn_t *mc, + int candidate, + Operation *op, + SlapReply *rs, + ldap_back_send_t sendok, + int dolock ) { metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; @@ -1446,10 +1578,16 @@ meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapRe switch ( method ) { case LDAP_AUTH_NONE: case LDAP_AUTH_SIMPLE: - rs->sr_err = ldap_sasl_bind( msc->msc_ld, + for (;;) { + rs->sr_err = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid ); - rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok ); + if ( rs->sr_err != LDAP_X_CONNECTING ) { + break; + } + ldap_pvt_thread_yield(); + } + rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock ); if ( rc == LDAP_SUCCESS ) { /* set rebind stuff in case of successful proxyAuthz bind, * so that referral chasing is attempted using the right @@ -1457,7 +1595,7 @@ meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapRe LDAP_BACK_CONN_ISBOUND_SET( msc ); ber_bvreplace( &msc->msc_bound_ndn, &binddn ); - if ( LDAP_BACK_SAVECRED( mi ) ) { + if ( META_BACK_TGT_SAVECRED( mt ) ) { if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); @@ -1476,3 +1614,140 @@ meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapRe return LDAP_BACK_CONN_ISBOUND( msc ); } + +/* + * Add controls; + * + * if any needs to be added, it is prepended to existing ones, + * in a newly allocated array. The companion function + * mi->mi_ldap_extra->controls_free() must be used to restore the original + * status of op->o_ctrls. + */ +int +meta_back_controls_add( + Operation *op, + SlapReply *rs, + metaconn_t *mc, + int candidate, + LDAPControl ***pctrls ) +{ + metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; + metatarget_t *mt = mi->mi_targets[ candidate ]; + metasingleconn_t *msc = &mc->mc_conns[ candidate ]; + + LDAPControl **ctrls = NULL; + /* set to the maximum number of controls this backend can add */ + LDAPControl c[ 2 ] = {{ 0 }}; + int n = 0, i, j1 = 0, j2 = 0; + + *pctrls = NULL; + + rs->sr_err = LDAP_SUCCESS; + + /* don't add controls if protocol is not LDAPv3 */ + switch ( mt->mt_version ) { + case LDAP_VERSION3: + break; + + case 0: + if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { + break; + } + /* fall thru */ + + default: + goto done; + } + + /* put controls that go __before__ existing ones here */ + + /* proxyAuthz for identity assertion */ + switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn, + mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) ) + { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j1++; + break; + + default: + goto done; + } + + /* put controls that go __after__ existing ones here */ + +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + /* session tracking */ + if ( META_BACK_TGT_ST_REQUEST( mt ) ) { + switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j2++; + break; + + default: + goto done; + } + } +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + + if ( rs->sr_err == SLAP_CB_CONTINUE ) { + rs->sr_err = LDAP_SUCCESS; + } + + /* if nothing to do, just bail out */ + if ( j1 == 0 && j2 == 0 ) { + goto done; + } + + assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) ); + + if ( op->o_ctrls ) { + for ( n = 0; op->o_ctrls[ n ]; n++ ) + /* just count ctrls */ ; + } + + ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ), + op->o_tmpmemctx ); + if ( j1 ) { + ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ]; + *ctrls[ 0 ] = c[ 0 ]; + for ( i = 1; i < j1; i++ ) { + ctrls[ i ] = &ctrls[ 0 ][ i ]; + *ctrls[ i ] = c[ i ]; + } + } + + i = 0; + if ( op->o_ctrls ) { + for ( i = 0; op->o_ctrls[ i ]; i++ ) { + ctrls[ i + j1 ] = op->o_ctrls[ i ]; + } + } + + n += j1; + if ( j2 ) { + ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1; + *ctrls[ n ] = c[ j1 ]; + for ( i = 1; i < j2; i++ ) { + ctrls[ n + i ] = &ctrls[ n ][ i ]; + *ctrls[ n + i ] = c[ i ]; + } + } + + ctrls[ n + j2 ] = NULL; + +done:; + if ( ctrls == NULL ) { + ctrls = op->o_ctrls; + } + + *pctrls = ctrls; + + return rs->sr_err; +} +