Operation *op,
SlapReply *rs,
metaconn_t *mc,
- int candidate );
+ int candidate,
+ int massage );
int
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
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;
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;
/*
* 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
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--;
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 );
}
LDAP_BACK_CONN_ISPRIV( mc ),
candidate == mc->mc_authz_target,
LDAP_BACK_DONTSEND );
-
} else {
/* can't do anything about it */
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,
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;
}
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 );
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;
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 );
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 );
}
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,
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? */
/*
* this target is no longer candidate
*/
- return 0;
+ return META_SEARCH_NOT_CANDIDATE;
}
break;
/*
* this target is no longer candidate
*/
- return 0;
+ return META_SEARCH_NOT_CANDIDATE;
}
}
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;
}
/*
/*
* this target is no longer candidate
*/
- rc = 0;
+ retcode = META_SEARCH_NOT_CANDIDATE;
goto done;
}
/*
* this target is no longer candidate
*/
- rc = 0;
+ retcode = META_SEARCH_NOT_CANDIDATE;
goto done;
}
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:;
free( mbase.bv_val );
}
- return rc;
+ return retcode;
}
int
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;
}
* get a LDAP_TIMELIMIT_EXCEEDED from
* one of them ...
*/
+get_result:;
rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
0, &tv, &res );
} 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;
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,
/* cleanup */
if ( references ) {
- ldap_value_free( references );
+ ber_memvfree( (void **)references );
}
if ( rs->sr_ctrls ) {
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,
LDAP_OPT_ERROR_NUMBER,
&rs->sr_err );
sres = slap_map_api2result( rs );
+ candidates[ i ].sr_type = REP_RESULT;
goto 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;