Commit 9bd90a74 authored by Ondřej Kuzník's avatar Ondřej Kuzník
Browse files

Fix a race on bind response processing.

During response processing, an upstream connection could be marked ready
after a different bind had already been allocated to it, thus allowing
two binds to be in progress on the same connection.
parent 485a1697
......@@ -374,8 +374,9 @@ request_bind( LloadConnection *client, LloadOperation *op )
if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
Debug( LDAP_DEBUG_ANY, "request_bind: "
"ber_alloc failed\n" );
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
CONNECTION_LOCK_DECREF(upstream);
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
upstream->c_state = LLOAD_C_READY;
if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) {
ber_memfree( upstream->c_sasl_bind_mech.bv_val );
BER_BVZERO( &upstream->c_sasl_bind_mech );
......@@ -605,7 +606,28 @@ handle_bind_response(
op->o_client_msgid, op->o_client_connid, result );
CONNECTION_LOCK(upstream);
if ( result != LDAP_SASL_BIND_IN_PROGRESS ) {
if ( !tavl_find( upstream->c_ops, op, operation_upstream_cmp ) ) {
/*
* operation might not be found because:
* - it has timed out (only happens when debugging/hung/...)
* a response has been sent for us, we must not send another
* - it has been abandoned (new bind, unbind)
* no response is expected
* - ???
*/
operation_destroy_from_upstream( op );
CONNECTION_UNLOCK(upstream);
return LDAP_SUCCESS;
}
if ( result == LDAP_SASL_BIND_IN_PROGRESS ) {
tavl_delete( &upstream->c_ops, op, operation_upstream_cmp );
op->o_upstream_msgid = 0;
op->o_upstream_refcnt++;
rc = tavl_insert(
&upstream->c_ops, op, operation_upstream_cmp, avl_dup_error );
assert( rc == LDAP_SUCCESS );
} else {
int sasl_finished = 0;
if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) {
sasl_finished = 1;
......@@ -620,14 +642,6 @@ handle_bind_response(
return finish_sasl_bind( upstream, op, ber );
}
upstream->c_state = LLOAD_C_READY;
} else {
if ( tavl_delete( &upstream->c_ops, op, operation_upstream_cmp ) ) {
op->o_upstream_msgid = 0;
op->o_upstream_refcnt++;
rc = tavl_insert( &upstream->c_ops, op, operation_upstream_cmp,
avl_dup_error );
assert( rc == LDAP_SUCCESS );
}
}
CONNECTION_UNLOCK(upstream);
......
......@@ -837,6 +837,15 @@ connection_timeout( LloadConnection *upstream, time_t threshold )
found_op = tavl_delete( &upstream->c_ops, op, operation_upstream_cmp );
assert( op == found_op );
if ( upstream->c_state == LLOAD_C_BINDING ) {
assert( op->o_tag == LDAP_REQ_BIND && upstream->c_ops == NULL );
upstream->c_state = LLOAD_C_READY;
if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) {
ber_memfree( upstream->c_sasl_bind_mech.bv_val );
BER_BVZERO( &upstream->c_sasl_bind_mech );
}
}
rc = tavl_insert( &ops, op, operation_upstream_cmp, avl_dup_error );
assert( rc == LDAP_SUCCESS );
......
......@@ -257,13 +257,6 @@ handle_one_response( LloadConnection *c )
CONNECTION_LOCK_DECREF(c);
op->o_upstream_refcnt--;
if ( !client || !op->o_upstream_refcnt ) {
if ( c->c_state == LLOAD_C_BINDING ) {
c->c_state = LLOAD_C_READY;
if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) {
ber_memfree( c->c_sasl_bind_mech.bv_val );
BER_BVZERO( &c->c_sasl_bind_mech );
}
}
operation_destroy_from_upstream( op );
}
} else {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment