From 852e4e310956addef57909f8e13d8b7e9a7e9260 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sat, 5 Nov 2005 14:44:43 +0000 Subject: [PATCH] allow per-target retry in searches; taint invalid connections; don't massage the pseudorootdn (ITS#4150) --- servers/slapd/back-meta/back-meta.h | 1 + servers/slapd/back-meta/bind.c | 62 +++++++++----------- servers/slapd/back-meta/conn.c | 19 ++++++ servers/slapd/back-meta/search.c | 90 ++++++++++++++++++++--------- 4 files changed, 111 insertions(+), 61 deletions(-) diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 5d1911d3ed..a37f60196f 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -184,6 +184,7 @@ typedef struct metaconn_t { struct slap_conn *mc_conn; ldap_pvt_thread_mutex_t mc_mutex; unsigned mc_refcnt; + int mc_tainted; struct berval mc_local_ndn; /* NOTE: msc_mscflags is used to recycle the #define diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index 3d59cf27d4..3d68674336 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -46,7 +46,8 @@ meta_back_single_bind( Operation *op, SlapReply *rs, metaconn_t *mc, - int candidate ); + int candidate, + int massage ); int meta_back_bind( Operation *op, SlapReply *rs ) @@ -124,6 +125,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) for ( i = 0; i < mi->mi_ntargets; i++ ) { int lerr; Operation op2 = *op; + int massage = 1; /* * Skip non-candidates @@ -177,9 +179,12 @@ meta_back_bind( Operation *op, SlapReply *rs ) op2.o_req_ndn = mi->mi_targets[ i ].mt_pseudorootdn; op2.orb_cred = mi->mi_targets[ i ].mt_pseudorootpw; op2.orb_method = LDAP_AUTH_SIMPLE; + + massage = 0; } - lerr = meta_back_single_bind( &op2, rs, mc, i ); + lerr = meta_back_single_bind( &op2, rs, mc, i, massage ); + if ( lerr != LDAP_SUCCESS ) { rs->sr_err = lerr; candidates[ i ].sr_tag = META_NOT_CANDIDATE; @@ -274,12 +279,12 @@ meta_back_single_bind( Operation *op, SlapReply *rs, metaconn_t *mc, - int candidate ) + int candidate, + int massage ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = &mi->mi_targets[ candidate ]; struct berval mdn = BER_BVNULL; - dncookie dc; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int msgid, rebinding = 0; @@ -300,14 +305,21 @@ meta_back_single_bind( /* * Rewrite the bind dn if needed */ - dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "bindDN"; + if ( massage ) { + dncookie dc; - if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - send_ldap_result( op, rs ); - return -1; + dc.target = mt; + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = "bindDN"; + + if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { + send_ldap_result( op, rs ); + return -1; + } + + } else { + mdn = op->o_req_dn; } /* FIXME: this fixes the bind problem right now; we need @@ -378,27 +390,7 @@ retry:; rc = slap_map_api2result( rs ); if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) { - ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex ); - if ( mc->mc_refcnt == 1 ) { - meta_clear_one_candidate( msc ); - LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); - - ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn ); - - /* mc here must be the regular mc, - * reset and ready for init */ - rc = meta_back_init_one_conn( op, rs, - mt, mc, msc, LDAP_BACK_CONN_ISPRIV( mc ), - candidate == mc->mc_authz_target, - LDAP_BACK_DONTSEND ); - - } else { - /* can't do anything about it */ - rc = 0; - } - - ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); - + rc = meta_back_retry( op, rs, mc, candidate, LDAP_BACK_DONTSEND ); if ( rc ) { if ( nretries > 0 ) { nretries--; @@ -552,6 +544,9 @@ retry:; rc = slap_map_api2result( rs ); if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) { + /* NOTE: we do not use meta_back_retry() here + * to avoid circular loops; mc_mutex is set + * by the caller */ if ( dolock ) { ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex ); } @@ -569,7 +564,6 @@ retry:; LDAP_BACK_CONN_ISPRIV( mc ), candidate == mc->mc_authz_target, LDAP_BACK_DONTSEND ); - } else { /* can't do anything about it */ @@ -685,7 +679,7 @@ meta_back_dobind( rootdn = mi->mi_targets[ i ].mt_pseudorootdn.bv_val; - rc = meta_back_single_bind( &op2, rs, mc, i ); + rc = meta_back_single_bind( &op2, rs, mc, i, 0 ); } else { rc = meta_back_single_dobind( op, rs, mc, i, diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index 8c341899d7..d005df178c 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -172,6 +172,7 @@ metaconn_alloc( mc->mc_authz_target = META_BOUND_NONE; ldap_pvt_thread_mutex_init( &mc->mc_mutex ); mc->mc_refcnt = 1; + mc->mc_tainted = 0; return mc; } @@ -447,6 +448,10 @@ retry_lock:; goto retry_lock; } + Debug( LDAP_DEBUG_ANY, "%s meta_back_retry: retrying uri=\"%s\" DN=\"%s\"\n", + op->o_log_prefix, mt->mt_uri, + BER_BVISNULL( &msc->msc_bound_ndn ) ? "" : msc->msc_bound_ndn.bv_val ); + meta_clear_one_candidate( msc ); LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); @@ -465,6 +470,10 @@ retry_lock:; ldap_pvt_thread_mutex_unlock( &mc->mc_mutex ); } + if ( rc != LDAP_SUCCESS ) { + mc->mc_tainted = 1; + } + ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); return rc == LDAP_SUCCESS ? 1 : 0; @@ -720,6 +729,13 @@ meta_back_getconn( mc = (metaconn_t *)avl_find( mi->mi_conntree, (caddr_t)&mc_curr, meta_back_conn_cmp ); if ( mc ) { + if ( mc->mc_tainted ) { + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "remote server unavailable"; + ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); + return NULL; + } + mc->mc_refcnt++; } ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); @@ -1122,5 +1138,8 @@ meta_back_release_conn( ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex ); assert( mc->mc_refcnt > 0 ); mc->mc_refcnt--; + if ( mc->mc_refcnt == 0 && mc->mc_tainted ) { + meta_back_conn_free( mc ); + } ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); } diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index d621b43307..e347169273 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -43,7 +43,13 @@ meta_send_entry( int i, LDAPMessage *e ); -static int +typedef enum meta_search_candidate_t { + META_SEARCH_ERR = -1, + META_SEARCH_NOT_CANDIDATE, + META_SEARCH_CANDIDATE +} meta_search_candidate_t; + +static meta_search_candidate_t meta_back_search_start( Operation *op, SlapReply *rs, @@ -61,6 +67,7 @@ meta_back_search_start( struct berval mfilter = BER_BVNULL; char **mapped_attrs = NULL; int rc; + meta_search_candidate_t retcode; struct timeval tv, *tvp = NULL; /* should we check return values? */ @@ -105,7 +112,7 @@ meta_back_search_start( /* * this target is no longer candidate */ - return 0; + return META_SEARCH_NOT_CANDIDATE; } break; @@ -145,7 +152,7 @@ meta_back_search_start( /* * this target is no longer candidate */ - return 0; + return META_SEARCH_NOT_CANDIDATE; } } @@ -161,14 +168,14 @@ meta_back_search_start( rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "Operation not allowed"; send_ldap_result( op, rs ); - return -1; + return META_SEARCH_ERR; case REWRITE_REGEXEC_ERR: /* * this target is no longer candidate */ - return 0; + return META_SEARCH_NOT_CANDIDATE; } /* @@ -185,7 +192,7 @@ meta_back_search_start( /* * this target is no longer candidate */ - rc = 0; + retcode = META_SEARCH_NOT_CANDIDATE; goto done; } @@ -198,7 +205,7 @@ meta_back_search_start( /* * this target is no longer candidate */ - rc = 0; + retcode = META_SEARCH_NOT_CANDIDATE; goto done; } @@ -211,11 +218,11 @@ meta_back_search_start( op->o_ctrls, NULL, tvp, op->ors_slimit, &candidates[ candidate ].sr_msgid ); if ( rc == LDAP_SUCCESS ) { - rc = 1; + retcode = META_SEARCH_CANDIDATE; } else { candidates[ candidate ].sr_msgid = -1; - rc = 0; + retcode = META_SEARCH_NOT_CANDIDATE; } done:; @@ -229,7 +236,7 @@ done:; free( mbase.bv_val ); } - return rc; + return retcode; } int @@ -284,14 +291,15 @@ meta_back_search( Operation *op, SlapReply *rs ) switch ( meta_back_search_start( op, rs, &dc, msc, i, candidates ) ) { - case 0: + case META_SEARCH_NOT_CANDIDATE: break; - case 1: + case META_SEARCH_CANDIDATE: + candidates[ i ].sr_type = REP_INTERMEDIATE; ++ncandidates; break; - case -1: + case META_SEARCH_ERR: rc = -1; goto finish; } @@ -386,6 +394,7 @@ meta_back_search( Operation *op, SlapReply *rs ) * get a LDAP_TIMELIMIT_EXCEEDED from * one of them ... */ +get_result:; rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid, 0, &tv, &res ); @@ -411,21 +420,37 @@ meta_back_search( Operation *op, SlapReply *rs ) } else if ( rc == -1 ) { really_bad:; /* something REALLY bad happened! */ - ( void )meta_clear_unused_candidates( op, -1 ); - rs->sr_err = LDAP_OTHER; - savepriv = op->o_private; - op->o_private = (void *)i; - send_ldap_result( op, rs ); - op->o_private = savepriv; - - /* anything else needs be done? */ - - /* FIXME: res should not need to be freed */ - assert( res == NULL ); + if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { + candidates[ i ].sr_type = REP_RESULT; + + if ( meta_back_retry( op, rs, mc, i, LDAP_BACK_DONTSEND ) ) { + switch ( meta_back_search_start( op, rs, &dc, msc, i, candidates ) ) + { + case META_SEARCH_CANDIDATE: + goto get_result; + + default: + rc = rs->sr_err = LDAP_OTHER; + goto finish; + } + } + } - goto finish; + /* + * When no candidates are left, + * the outer cycle finishes + */ + candidates[ i ].sr_msgid = -1; + --ncandidates; + rs->sr_err = candidates[ i ].sr_err = LDAP_OTHER; + rs->sr_text = "remote server unavailable"; } else if ( rc == LDAP_RES_SEARCH_ENTRY ) { + if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { + /* don't retry any more... */ + candidates[ i ].sr_type = REP_RESULT; + } + if ( --op->ors_slimit == -1 ) { ldap_msgfree( res ); res = NULL; @@ -477,6 +502,11 @@ really_bad:; char **references = NULL; int cnt; + if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { + /* don't retry any more... */ + candidates[ i ].sr_type = REP_RESULT; + } + is_ok++; rc = ldap_parse_reference( msc->msc_ld, res, @@ -525,7 +555,7 @@ really_bad:; /* cleanup */ if ( references ) { - ldap_value_free( references ); + ber_memvfree( (void **)references ); } if ( rs->sr_ctrls ) { @@ -537,6 +567,11 @@ really_bad:; char buf[ SLAP_TEXT_BUFLEN ]; char **references = NULL; + if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { + /* don't retry any more... */ + candidates[ i ].sr_type = REP_RESULT; + } + if ( ldap_parse_result( msc->msc_ld, res, &candidates[ i ].sr_err, @@ -550,6 +585,7 @@ really_bad:; LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); sres = slap_map_api2result( rs ); + candidates[ i ].sr_type = REP_RESULT; goto really_bad; } @@ -611,7 +647,7 @@ really_bad:; ( void )ldap_back_referral_result_rewrite( &dc, sr_ref ); /* cleanup */ - ldap_value_free( references ); + ber_memvfree( (void **)references ); if ( rs->sr_v2ref == NULL ) { rs->sr_v2ref = sr_ref; -- 2.39.5