rework compare

fix several minor issues with using dangling pointers and uninitialized data
fix caching of privileged connections
fix issues with unresponsive target failures during search
This commit is contained in:
Pierangelo Masarati 2006-11-05 12:05:47 +00:00
parent fd0176e49c
commit efb04832bd
7 changed files with 256 additions and 349 deletions

View File

@ -494,11 +494,6 @@ meta_clear_one_candidate(
metaconn_t *mc, metaconn_t *mc,
int candidate ); int candidate );
extern int
meta_clear_candidates(
Operation *op,
metaconn_t *mc );
/* /*
* Dn cache stuff (experimental) * Dn cache stuff (experimental)
*/ */

View File

@ -253,6 +253,7 @@ retry_lock:;
ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
if ( isroot ) { if ( isroot ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
mc->mc_conn = LDAP_BACK_PCONN_SET( op ); mc->mc_conn = LDAP_BACK_PCONN_SET( op );
} }
lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
@ -262,9 +263,8 @@ retry_lock:;
#endif /* META_BACK_PRINT_CONNTREE */ #endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( lerr == -1 ) { if ( lerr == -1 ) {
meta_clear_candidates( op, mc );
/* we can do this because mc_refcnt == 1 */ /* we can do this because mc_refcnt == 1 */
assert( mc->mc_refcnt == 1 );
mc->mc_refcnt = 0; mc->mc_refcnt = 0;
meta_back_conn_free( mc ); meta_back_conn_free( mc );
mc = NULL; mc = NULL;
@ -396,10 +396,10 @@ retry:;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
assert( LDAP_BACK_CONN_BINDING( msc ) ); assert( LDAP_BACK_CONN_BINDING( msc ) );
#if 0 #ifdef DEBUG_205
Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n", 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 ); op->o_log_prefix, candidate, (void *)msc->msc_ld );
#endif #endif /* DEBUG_205 */
ldap_unbind_ext( msc->msc_ld, NULL, NULL ); ldap_unbind_ext( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL; msc->msc_ld = NULL;
@ -575,7 +575,7 @@ meta_back_single_dobind(
!op->o_do_not_cache && !op->o_do_not_cache &&
( BER_BVISNULL( &msc->msc_bound_ndn ) || ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
BER_BVISEMPTY( &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 ) ) ) ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
{ {
(void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok ); (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok );

View File

@ -189,10 +189,14 @@ meta_clear_one_candidate(
if ( msc->msc_ld ) { if ( msc->msc_ld ) {
#if 0 #ifdef DEBUG_205
Debug( LDAP_DEBUG_ANY, "### %s meta_clear_one_candidate ldap_unbind_ext[%d] mc=%p\n", char buf[ BUFSIZ ];
op ? op->o_log_prefix : "", candidate, (void *)mc );
#endif snprintf( buf, sizeof( buf ), "meta_clear_one_candidate ldap_unbind_ext[%d] mc=%p ld=%p",
candidate, (void *)mc, (void *)msc->msc_ld );
Debug( LDAP_DEBUG_ANY, "### %s %s\n",
op ? op->o_log_prefix : "", buf, 0 );
#endif /* DEBUG_205 */
ldap_unbind_ext( msc->msc_ld, NULL, NULL ); ldap_unbind_ext( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL; msc->msc_ld = NULL;
@ -212,20 +216,3 @@ meta_clear_one_candidate(
return 0; return 0;
} }
/*
* meta_clear_candidates
*
* clears all candidates
*/
int
meta_clear_candidates( Operation *op, metaconn_t *mc )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
int c;
for ( c = 0; c < mi->mi_ntargets; c++ ) {
meta_clear_one_candidate( op, mc, c );
}
return 0;
}

View File

@ -35,62 +35,38 @@ int
meta_back_compare( Operation *op, SlapReply *rs ) meta_back_compare( Operation *op, SlapReply *rs )
{ {
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metaconn_t *mc = NULL; metatarget_t *mt;
char *match = NULL, metaconn_t *mc;
*err = NULL; int rc = 0;
struct berval mmatch = BER_BVNULL; int candidate = -1;
int ncandidates = 0, struct berval mdn = BER_BVNULL;
last = 0,
i,
count = 0,
rc,
cres = LDAP_SUCCESS,
rres = LDAP_SUCCESS,
*msgid;
dncookie dc; dncookie dc;
struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
struct berval mapped_value = op->orc_ava->aa_value;
int msgid;
int do_retry = 1;
LDAPControl **ctrls = NULL;
SlapReply *candidates = meta_back_candidates_get( op ); mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR );
if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) { if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
return rs->sr_err; return rs->sr_err;
} }
msgid = ch_calloc( sizeof( int ), mi->mi_ntargets ); assert( mc->mc_conns[ candidate ].msc_ld != NULL );
if ( msgid == NULL ) {
send_ldap_error( op, rs, LDAP_OTHER, NULL );
rc = LDAP_OTHER;
goto done;
}
/* /*
* start an asynchronous compare for each candidate target * Rewrite the modify dn, if needed
*/ */
mt = mi->mi_targets[ candidate ];
dc.target = mt;
dc.conn = op->o_conn; dc.conn = op->o_conn;
dc.rs = rs; dc.rs = rs;
dc.ctx = "compareDN"; dc.ctx = "compareDN";
for ( i = 0; i < mi->mi_ntargets; i++ ) {
struct berval mdn = BER_BVNULL;
struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
struct berval mapped_value = op->orc_ava->aa_value;
metatarget_t *mt = mi->mi_targets[ i ];
LDAPControl **ctrls = NULL;
if ( ! META_IS_CANDIDATE( &candidates[ i ] ) ) {
msgid[ i ] = -1;
continue;
}
/*
* Rewrite the compare dn, if needed
*/
dc.target = mt;
switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
case LDAP_UNWILLING_TO_PERFORM: case LDAP_UNWILLING_TO_PERFORM:
rc = 1; rc = 1;
goto finish; goto cleanup;
default: default:
break; break;
@ -104,9 +80,10 @@ meta_back_compare( Operation *op, SlapReply *rs )
&op->orc_ava->aa_value, &op->orc_ava->aa_value,
&mapped_value, BACKLDAP_MAP ); &mapped_value, BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped_value ) || mapped_value.bv_val[0] == '\0' ) { if ( BER_BVISNULL( &mapped_value ) || BER_BVISEMPTY( &mapped_value ) ) {
continue; goto cleanup;
} }
/* /*
* else try to remap the attribute * else try to remap the attribute
*/ */
@ -114,8 +91,8 @@ meta_back_compare( Operation *op, SlapReply *rs )
ldap_back_map( &mt->mt_rwmap.rwm_at, ldap_back_map( &mt->mt_rwmap.rwm_at,
&op->orc_ava->aa_desc->ad_cname, &op->orc_ava->aa_desc->ad_cname,
&mapped_attr, BACKLDAP_MAP ); &mapped_attr, BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped_attr ) || mapped_attr.bv_val[0] == '\0' ) { if ( BER_BVISNULL( &mapped_attr ) || BER_BVISEMPTY( &mapped_attr ) ) {
continue; goto cleanup;
} }
if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
@ -126,7 +103,7 @@ meta_back_compare( Operation *op, SlapReply *rs )
{ {
case LDAP_UNWILLING_TO_PERFORM: case LDAP_UNWILLING_TO_PERFORM:
rc = 1; rc = 1;
goto finish; goto cleanup;
default: default:
break; break;
@ -134,219 +111,45 @@ meta_back_compare( Operation *op, SlapReply *rs )
} }
} }
retry:;
ctrls = op->o_ctrls; ctrls = op->o_ctrls;
if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ i ].msc_bound_ndn, rc = ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn,
mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS ) mt->mt_version, &mt->mt_idassert, op, rs, &ctrls );
{ if ( rc != LDAP_SUCCESS ) {
continue; send_ldap_result( op, rs );
goto cleanup;
} }
/* rs->sr_err = ldap_compare_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val,
* the compare op is spawned across the targets and the first
* that returns determines the result; a constraint on unicity
* of the result ought to be enforced
*/
rc = ldap_compare_ext( mc->mc_conns[ i ].msc_ld, mdn.bv_val,
mapped_attr.bv_val, &mapped_value, mapped_attr.bv_val, &mapped_value,
ctrls, NULL, &msgid[ i ] ); ctrls, NULL, &msgid );
rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
mt->mt_timeout[ SLAP_OP_COMPARE ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
/* if the identity changed, there might be need to re-authz */
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
goto retry;
}
}
cleanup:;
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) { if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val ); free( mdn.bv_val );
BER_BVZERO( &mdn );
} }
if ( mapped_attr.bv_val != op->orc_ava->aa_desc->ad_cname.bv_val ) { if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) {
free( mapped_attr.bv_val );
BER_BVZERO( &mapped_attr );
}
if ( mapped_value.bv_val != op->orc_ava->aa_value.bv_val ) {
free( mapped_value.bv_val ); free( mapped_value.bv_val );
BER_BVZERO( &mapped_value );
} }
if ( rc != LDAP_SUCCESS ) { if ( mc ) {
/* FIXME: what should we do with the error? */
continue;
}
++ncandidates;
}
/*
* wait for replies
*/
for ( rc = 0, count = 0; ncandidates > 0; ) {
/*
* FIXME: should we check for abandon?
*/
for ( i = 0; i < mi->mi_ntargets; i++ ) {
metasingleconn_t *msc = &mc->mc_conns[ i ];
int lrc;
LDAPMessage *res = NULL;
struct timeval tv;
LDAP_BACK_TV_SET( &tv );
if ( msgid[ i ] == -1 ) {
continue;
}
lrc = ldap_result( msc->msc_ld, msgid[ i ],
LDAP_MSG_ALL, &tv, &res );
switch ( lrc ) {
case 0:
assert( res == NULL );
continue;
case -1:
/* we do not retry in this case;
* only for unique operations... */
ldap_get_option( msc->msc_ld,
LDAP_OPT_RESULT_CODE, &rs->sr_err );
rres = slap_map_api2result( rs );
rres = rc;
rc = -1;
goto finish;
default:
/* only touch when activity actually took place... */
/* NOTE: no mutex because there's only a loose requirement
* to bump it up... */
if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
msc->msc_time = op->o_time;
}
break;
}
if ( lrc == LDAP_RES_COMPARE ) {
if ( count > 0 ) {
rres = LDAP_OTHER;
rc = -1;
goto finish;
}
/* FIXME: matched? referrals? response controls? */
rc = ldap_parse_result( msc->msc_ld, res,
&rs->sr_err,
NULL, NULL, NULL, NULL, 1 );
if ( rc != LDAP_SUCCESS ) {
rres = rc;
rc = -1;
goto finish;
}
switch ( rs->sr_err ) {
case LDAP_COMPARE_TRUE:
case LDAP_COMPARE_FALSE:
/*
* true or false, got it;
* sending to cache ...
*/
if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
( void )meta_dncache_update_entry( &mi->mi_cache, &op->o_req_ndn, i );
}
count++;
rc = 0;
break;
default:
rres = slap_map_api2result( rs );
if ( err != NULL ) {
free( err );
}
ldap_get_option( msc->msc_ld,
LDAP_OPT_DIAGNOSTIC_MESSAGE, &err );
if ( match != NULL ) {
free( match );
}
ldap_get_option( msc->msc_ld,
LDAP_OPT_MATCHED_DN, &match );
last = i;
break;
}
msgid[ i ] = -1;
--ncandidates;
} else {
msgid[ i ] = -1;
--ncandidates;
if ( res ) {
ldap_msgfree( res );
}
break;
}
}
}
finish:;
/*
* Rewrite the matched portion of the search base, if required
*
* FIXME: only the last one gets caught!
*/
if ( count == 1 ) {
if ( match != NULL ) {
free( match );
match = NULL;
}
/*
* the result of the compare is assigned to the res code
* that will be returned
*/
rres = cres;
/*
* At least one compare failed with matched portion,
* and none was successful
*/
} else if ( match != NULL && match[ 0 ] != '\0' ) {
struct berval matched, pmatched;
ber_str2bv( match, 0, 0, &matched );
dc.ctx = "matchedDN";
ldap_back_dn_massage( &dc, &matched, &mmatch );
if ( dnPretty( NULL, &mmatch, &pmatched, NULL ) == LDAP_SUCCESS ) {
if ( mmatch.bv_val != match ) {
free( mmatch.bv_val );
}
mmatch = pmatched;
}
}
if ( rres != LDAP_SUCCESS ) {
rs->sr_err = rres;
}
rs->sr_matched = mmatch.bv_val;
send_ldap_result( op, rs );
rs->sr_matched = NULL;
if ( match != NULL ) {
if ( mmatch.bv_val != match ) {
free( mmatch.bv_val );
}
free( match );
}
if ( msgid ) {
free( msgid );
}
done:;
meta_back_release_conn( op, mc ); meta_back_release_conn( op, mc );
}
return rc; return rs->sr_err;
} }

View File

@ -156,11 +156,12 @@ ravl_print( Avlnode *root, int depth )
} }
mc = (metaconn_t *)root->avl_data; mc = (metaconn_t *)root->avl_data;
fprintf( stderr, "mc=%p local=\"%s\" conn=%p %s refcnt=%d\n", fprintf( stderr, "mc=%p local=\"%s\" conn=%p %s refcnt=%d%s\n",
(void *)mc, (void *)mc,
mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "", mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",
(void *)mc->mc_conn, (void *)mc->mc_conn,
avl_bf2str( root->avl_bf ), mc->mc_refcnt ); avl_bf2str( root->avl_bf ), mc->mc_refcnt,
LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "" );
ravl_print( root->avl_left, depth + 1 ); ravl_print( root->avl_left, depth + 1 );
} }
@ -424,10 +425,10 @@ retry:;
|| ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) ) || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) )
{ {
#if 0 #ifdef DEBUG_205
Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(TLS) ldap_unbind_ext[%d] ld=%p\n", Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(TLS) ldap_unbind_ext[%d] ld=%p\n",
op->o_log_prefix, candidate, (void *)msc->msc_ld ); op->o_log_prefix, candidate, (void *)msc->msc_ld );
#endif #endif /* DEBUG_205 */
ldap_unbind_ext( msc->msc_ld, NULL, NULL ); ldap_unbind_ext( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL; msc->msc_ld = NULL;
@ -464,8 +465,6 @@ retry:;
ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv ); ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv );
} }
LDAP_BACK_CONN_ISPRIV_SET( msc );
} else { } else {
if ( !BER_BVISNULL( &msc->msc_cred ) ) { if ( !BER_BVISNULL( &msc->msc_cred ) ) {
memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
@ -492,10 +491,10 @@ retry:;
&msc->msc_bound_ndn ) ) &msc->msc_bound_ndn ) )
{ {
#if 0 #ifdef DEBUG_205
Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(rewrite) ldap_unbind_ext[%d] ld=%p\n", Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(rewrite) ldap_unbind_ext[%d] ld=%p\n",
op->o_log_prefix, candidate, (void *)msc->msc_ld ); op->o_log_prefix, candidate, (void *)msc->msc_ld );
#endif #endif /* DEBUG_205 */
ldap_unbind_ext( msc->msc_ld, NULL, NULL ); ldap_unbind_ext( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL; msc->msc_ld = NULL;
@ -923,7 +922,8 @@ retry_lock:;
op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) ); op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
} }
/* Don't reuse connections while they're still binding */ /* Don't reuse connections while they're still binding
* NOTE: only makes sense for binds */
if ( LDAP_BACK_CONN_BINDING( mc ) ) { if ( LDAP_BACK_CONN_BINDING( mc ) ) {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
ldap_pvt_thread_yield(); ldap_pvt_thread_yield();
@ -959,12 +959,12 @@ retry_lock:;
} }
break; break;
case LDAP_REQ_COMPARE:
case LDAP_REQ_DELETE: case LDAP_REQ_DELETE:
case LDAP_REQ_MODIFY: case LDAP_REQ_MODIFY:
/* just a unique candidate */ /* just a unique candidate */
break; break;
case LDAP_REQ_COMPARE:
case LDAP_REQ_SEARCH: case LDAP_REQ_SEARCH:
/* allow multiple candidates for the searchBase */ /* allow multiple candidates for the searchBase */
op_type = META_OP_ALLOW_MULTIPLE; op_type = META_OP_ALLOW_MULTIPLE;
@ -990,6 +990,13 @@ retry_lock:;
if ( sendok & LDAP_BACK_BINDING ) { if ( sendok & LDAP_BACK_BINDING ) {
LDAP_BACK_CONN_BINDING_SET( mc ); LDAP_BACK_CONN_BINDING_SET( mc );
} }
if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
}
} else if ( 0 ) {
/* TODO: if any of the connections is binding,
* release mc and create a new one */
} }
for ( i = 0; i < mi->mi_ntargets; i++ ) { for ( i = 0; i < mi->mi_ntargets; i++ ) {
@ -1121,12 +1128,11 @@ retry_lock2:;
(caddr_t)&mc_curr, meta_back_conndn_cmp ); (caddr_t)&mc_curr, meta_back_conndn_cmp );
if ( mc != NULL ) { if ( mc != NULL ) {
/* Don't reuse connections while they're still binding */ /* Don't reuse connections while they're still binding */
if ( LDAP_BACK_CONN_BINDING( mc ) ) { if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
ldap_pvt_thread_yield(); ldap_pvt_thread_yield();
goto retry_lock2; goto retry_lock2;
} }
mc->mc_refcnt++; mc->mc_refcnt++;
} }
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
@ -1142,6 +1148,9 @@ retry_lock2:;
if ( sendok & LDAP_BACK_BINDING ) { if ( sendok & LDAP_BACK_BINDING ) {
LDAP_BACK_CONN_BINDING_SET( mc ); LDAP_BACK_CONN_BINDING_SET( mc );
} }
if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
}
} }
} }
@ -1197,8 +1206,8 @@ retry_lock2:;
mc->mc_conn = mc_curr.mc_conn; mc->mc_conn = mc_curr.mc_conn;
ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn );
new_conn = 1; new_conn = 1;
if ( sendok & LDAP_BACK_BINDING ) { if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
LDAP_BACK_CONN_BINDING_SET( mc ); LDAP_BACK_CONN_ISPRIV_SET( mc );
} }
} }
@ -1404,7 +1413,6 @@ meta_back_release_conn_lock(
} }
assert( mc->mc_refcnt > 0 ); assert( mc->mc_refcnt > 0 );
mc->mc_refcnt--; mc->mc_refcnt--;
LDAP_BACK_CONN_BINDING_CLEAR( mc );
/* NOTE: the connection is removed if either it is tainted /* NOTE: the connection is removed if either it is tainted
* or if it is shared and no one else is using it. This needs * or if it is shared and no one else is using it. This needs
* to occur because for intrinsic reasons cached connections * to occur because for intrinsic reasons cached connections
@ -1428,8 +1436,14 @@ meta_back_release_conn_lock(
#endif /* META_BACK_PRINT_CONNTREE */ #endif /* META_BACK_PRINT_CONNTREE */
if ( mc->mc_refcnt == 0 ) { if ( mc->mc_refcnt == 0 ) {
meta_back_conn_free( mc ); meta_back_conn_free( mc );
mc = NULL;
} }
} }
if ( mc != NULL ) {
LDAP_BACK_CONN_BINDING_CLEAR( mc );
}
if ( dolock ) { if ( dolock ) {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
} }

View File

@ -170,7 +170,6 @@ meta_back_conn_free(
{ {
metaconn_t *mc = v_mc; metaconn_t *mc = v_mc;
int ntargets; int ntargets;
Operation op;
assert( mc != NULL ); assert( mc != NULL );
assert( mc->mc_refcnt == 0 ); assert( mc->mc_refcnt == 0 );

View File

@ -85,7 +85,8 @@ meta_search_dobind_init(
meta_search_candidate_t retcode; meta_search_candidate_t retcode;
Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n", op->o_log_prefix, candidate, 0 ); Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
op->o_log_prefix, candidate, 0 );
/* /*
* all the targets are already bound as pseudoroot * all the targets are already bound as pseudoroot
@ -98,17 +99,55 @@ meta_search_dobind_init(
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) { if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
/* already bound (or anonymous) */ /* already bound (or anonymous) */
#ifdef DEBUG_205
char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
int bound = 0;
if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
bound = 1;
}
snprintf( buf, sizeof( buf ), " mc=%p lc=%p%s DN=\"%s\"",
(void *)mc, (void *)msc->msc_ld,
bound ? " bound" : " anonymous",
bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
} else if ( LDAP_BACK_CONN_BINDING( msc ) ) { } else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
/* another thread is binding the target for this conn; wait */ /* another thread is binding the target for this conn; wait */
#ifdef DEBUG_205
char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
snprintf( buf, sizeof( buf ), " mc=%p lc=%p needbind",
(void *)mc, (void *)msc->msc_ld );
Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */
candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND; candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
retcode = META_SEARCH_NEED_BIND; retcode = META_SEARCH_NEED_BIND;
} else { } else {
/* we'll need to bind the target for this conn */ /* we'll need to bind the target for this conn */
#ifdef DEBUG_205
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
(void *)mc, (void *)msc->msc_ld );
Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */
LDAP_BACK_CONN_BINDING_SET( msc ); LDAP_BACK_CONN_BINDING_SET( msc );
} }
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( retcode != META_SEARCH_BINDING ) { if ( retcode != META_SEARCH_BINDING ) {
@ -120,8 +159,8 @@ meta_search_dobind_init(
* state, with eventual connection expiration or invalidation) * state, with eventual connection expiration or invalidation)
* it was not initialized as expected */ * it was not initialized as expected */
Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] ld=NULL\n", Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
op->o_log_prefix, candidate, 0 ); op->o_log_prefix, candidate, (void *)mc );
rc = meta_back_init_one_conn( op, rs, *mcp, candidate, rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND ); LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND );
@ -185,6 +224,18 @@ meta_search_dobind_init(
rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred, rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
NULL, NULL, &candidates[ candidate ].sr_msgid ); NULL, NULL, &candidates[ candidate ].sr_msgid );
#ifdef DEBUG_205
{
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
Debug( LDAP_DEBUG_ANY, "### %s %s\n",
op->o_log_prefix, buf, 0 );
}
#endif /* DEBUG_205 */
switch ( rc ) { switch ( rc ) {
case LDAP_SUCCESS: case LDAP_SUCCESS:
assert( candidates[ candidate ].sr_msgid >= 0 ); assert( candidates[ candidate ].sr_msgid >= 0 );
@ -222,9 +273,9 @@ other:;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
} else { } else {
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_NOT_CANDIDATE; retcode = META_SEARCH_NOT_CANDIDATE;
} }
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
break; break;
} }
@ -271,17 +322,22 @@ meta_search_dobind_result(
} else { } else {
/* FIXME: check if bound as idassert authcDN! */ /* FIXME: check if bound as idassert authcDN! */
if ( be_isroot( op ) ) { if ( BER_BVISNULL( &msc->msc_bound_ndn )
LDAP_BACK_CONN_ISBOUND_SET( msc ); || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
} else { {
LDAP_BACK_CONN_ISANON_SET( msc ); LDAP_BACK_CONN_ISANON_SET( msc );
} else {
LDAP_BACK_CONN_ISBOUND_SET( msc );
} }
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
} }
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
META_BINDING_CLEAR( &candidates[ candidate ] ); META_BINDING_CLEAR( &candidates[ candidate ] );
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
return retcode; return retcode;
} }
@ -317,6 +373,7 @@ meta_back_search_start(
if ( META_BACK_ONERR_STOP( mi ) ) { if ( META_BACK_ONERR_STOP( mi ) ) {
return META_SEARCH_ERR; return META_SEARCH_ERR;
} }
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
return META_SEARCH_NOT_CANDIDATE; return META_SEARCH_NOT_CANDIDATE;
} }
@ -567,8 +624,17 @@ getconn:;
* Inits searches * Inits searches
*/ */
for ( i = 0; i < mi->mi_ntargets; i++ ) { for ( i = 0; i < mi->mi_ntargets; i++ ) {
/* reset sr_msgid; it is used in most loops
* to check if that target is still to be considered */
candidates[ i ].sr_msgid = META_MSGID_IGNORE; candidates[ i ].sr_msgid = META_MSGID_IGNORE;
/* a target is marked as candidate by meta_back_getconn();
* if for any reason (an error, it's over or so) it is
* no longer active, sr_msgid is set to META_MSGID_IGNORE
* but it remains candidate, which means it has been active
* at some point during the operation. This allows to
* use its response code and more to compute the final
* response */
if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
continue; continue;
} }
@ -589,6 +655,7 @@ getconn:;
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) ) switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
{ {
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
break; break;
case META_SEARCH_NEED_BIND: case META_SEARCH_NEED_BIND:
@ -612,15 +679,31 @@ getconn:;
} }
if ( ncandidates > 0 && needbind == ncandidates ) { if ( ncandidates > 0 && needbind == ncandidates ) {
assert( ( sendok & LDAP_BACK_BINDING ) == 0 ); /*
* give up the second time...
*
* NOTE: this should not occur the second time, since a fresh
* connection has ben created; however, targets may also
* need bind because the bind timed out or so.
*/
if ( sendok & LDAP_BACK_BINDING ) {
Debug( LDAP_DEBUG_ANY,
"%s meta_back_search: unable to initialize conn\n",
op->o_log_prefix, 0, 0 );
rs->sr_err = LDAP_UNAVAILABLE;
rs->sr_text = "unable to initialize connection to remote targets";
send_ldap_result( op, rs );
rc = -1;
goto finish;
}
/* FIXME: better create a separate connection? */ /* FIXME: better create a separate connection? */
sendok |= LDAP_BACK_BINDING; sendok |= LDAP_BACK_BINDING;
#if 0 #ifdef DEBUG_205
Debug( LDAP_DEBUG_TRACE, "*** %s drop mc=%p create new connection\n", Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
op->o_log_prefix, mc, 0 ); op->o_log_prefix, (void *)mc, 0 );
#endif #endif /* DEBUG_205 */
meta_back_release_conn( op, mc ); meta_back_release_conn( op, mc );
mc = NULL; mc = NULL;
@ -634,7 +717,7 @@ getconn:;
initial_candidates = ncandidates; initial_candidates = ncandidates;
if ( LogTest( LDAP_DEBUG_TRACE ) ) { if ( LogTest( LDAP_DEBUG_TRACE ) ) {
char cnd[ BUFSIZ ]; char cnd[ SLAP_TEXT_BUFLEN ];
int c; int c;
for ( c = 0; c < mi->mi_ntargets; c++ ) { for ( c = 0; c < mi->mi_ntargets; c++ ) {
@ -719,10 +802,12 @@ getconn:;
metasingleconn_t *msc = &mc->mc_conns[ i ]; metasingleconn_t *msc = &mc->mc_conns[ i ];
LDAPMessage *res = NULL, *msg; LDAPMessage *res = NULL, *msg;
/* if msgid is invalid, don't ldap_result() */
if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) { if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
continue; continue;
} }
/* if target still needs bind, retry */
if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) { if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) {
meta_search_candidate_t retcode; meta_search_candidate_t retcode;
@ -806,6 +891,23 @@ getconn:;
break; break;
} }
#ifdef DEBUG_205
if ( msc->msc_ld == NULL ) {
char buf[ SLAP_TEXT_BUFLEN ];
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
snprintf( buf, sizeof( buf ),
"%s meta_back_search[%ld] mc=%p msgid=%d%s%s\n",
op->o_log_prefix, (long)i, (void *)mc,
candidates[ i ].sr_msgid,
META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "" );
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
}
#endif /* DEBUG_205 */
/* /*
* FIXME: handle time limit as well? * FIXME: handle time limit as well?
* Note that target servers are likely * Note that target servers are likely
@ -833,7 +935,8 @@ really_bad:;
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) ) switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
{ {
case META_SEARCH_CANDIDATE: case META_SEARCH_CANDIDATE:
break; /* get back into business... */
continue;
/* means that failed but onerr == continue */ /* means that failed but onerr == continue */
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
@ -855,6 +958,7 @@ really_bad:;
default: default:
/* unrecoverable error */ /* unrecoverable error */
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
rc = rs->sr_err = LDAP_OTHER; rc = rs->sr_err = LDAP_OTHER;
goto finish; goto finish;
} }
@ -1225,11 +1329,16 @@ really_bad:;
if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) { if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
/* if still binding, destroy */ /* if still binding, destroy */
#if 0 #ifdef DEBUG_205
Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(abandon) " char buf[ SLAP_TEXT_BUFLEN ];
"ldap_unbind_ext[%ld] ld=%p\n",
op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld ); snprintf( buf, sizeof( buf), "%s meta_back_search(abandon) "
#endif "ldap_unbind_ext[%ld] mc=%p ld=%p",
op->o_log_prefix, i, (void *)mc,
(void *)mc->mc_conns[i].msc_ld );
Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 );
#endif /* DEBUG_205 */
ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL ); ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL );
mc->mc_conns[ i ].msc_ld = NULL; mc->mc_conns[ i ].msc_ld = NULL;
@ -1273,7 +1382,7 @@ really_bad:;
#if 0 #if 0
if ( LogTest( LDAP_DEBUG_TRACE ) ) { if ( LogTest( LDAP_DEBUG_TRACE ) ) {
char buf[ BUFSIZ ]; char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ), "%s %ld.%06ld %d/%d mc=%p", snprintf( buf, sizeof( buf ), "%s %ld.%06ld %d/%d mc=%p",
op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec, op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec,
@ -1390,8 +1499,8 @@ really_bad:;
#if 0 #if 0
{ {
char buf[BUFSIZ]; char buf[ SLAP_TEXT_BUFLEN ];
char cnd[BUFSIZ]; char cnd[ SLAP_TEXT_BUFLEN ];
int i; int i;
for ( i = 0; i < mi->mi_ntargets; i++ ) { for ( i = 0; i < mi->mi_ntargets; i++ ) {
@ -1449,11 +1558,11 @@ finish:;
assert( candidates[ i ].sr_msgid >= 0 ); assert( candidates[ i ].sr_msgid >= 0 );
assert( mc->mc_conns[ i ].msc_ld != NULL ); assert( mc->mc_conns[ i ].msc_ld != NULL );
#if 0 #ifdef DEBUG_205
Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) " Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) "
"ldap_unbind_ext[%ld] ld=%p\n", "ldap_unbind_ext[%ld] ld=%p\n",
op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld ); op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld );
#endif #endif /* DEBUG_205 */
/* if still binding, destroy */ /* if still binding, destroy */
ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL ); ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL );