Commit 21a22d1b authored by Ondřej Kuzník's avatar Ondřej Kuzník Committed by Ondřej Kuzník
Browse files

Refactor request parsing and sending.

We have to do most of out processing before we send the request over to
the upstream. If we don't, we might be too late and the response might
have arrived already.
parent ddd1acc3
......@@ -29,99 +29,20 @@
* upstream's c_io_mutex.
*/
static int
client_bind( LloadOperation *op )
client_bind(
LloadOperation *op,
struct berval *binddn,
ber_tag_t tag,
struct berval *auth )
{
LloadConnection *client = op->o_client, *upstream = op->o_upstream;
BerElement *ber, *copy = NULL;
BerValue binddn;
ber_tag_t tag;
ber_int_t version;
ber = upstream->c_pendingber;
if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
Debug( LDAP_DEBUG_ANY, "request_bind: "
"ber_alloc failed\n" );
goto fail;
}
upstream->c_pendingber = ber;
if ( (copy = ber_alloc()) == NULL ) {
goto fail;
}
ber_init2( copy, &op->o_request, 0 );
tag = ber_get_int( copy, &version );
if ( tag == LBER_ERROR ) {
Debug( LDAP_DEBUG_PACKETS, "request_bind: "
"failed to parse version field\n" );
goto fail;
} else if ( version != LDAP_VERSION3 ) {
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
operation_send_reject(
op, LDAP_PROTOCOL_ERROR, "LDAP version unsupported", 1 );
ber_free( copy, 0 );
return 0;
}
tag = ber_get_stringbv( copy, &binddn, LBER_BV_NOTERM );
if ( tag == LBER_ERROR ) {
Debug( LDAP_DEBUG_PACKETS, "request_bind: "
"failed to parse bind name field\n" );
goto fail;
}
CONNECTION_LOCK(client);
if ( !BER_BVISNULL( &client->c_auth ) ) {
ch_free( client->c_auth.bv_val );
}
if ( !BER_BVISEMPTY( &binddn ) ) {
char *ptr;
client->c_auth.bv_len = STRLENOF("dn:") + binddn.bv_len;
client->c_auth.bv_val = ch_malloc( client->c_auth.bv_len + 1 );
ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" );
ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len );
*ptr = '\0';
} else {
BER_BVZERO( &client->c_auth );
}
CONNECTION_UNLOCK(client);
CONNECTION_LOCK(upstream);
op->o_upstream_msgid = upstream->c_next_msgid++;
LloadConnection *upstream = op->o_upstream;
ber_printf( ber, "t{titOtO}", LDAP_TAG_MESSAGE,
ber_printf( upstream->c_pendingber, "t{titOtO}", LDAP_TAG_MESSAGE,
LDAP_TAG_MSGID, op->o_upstream_msgid,
LDAP_REQ_BIND, &op->o_request,
LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) );
Debug( LDAP_DEBUG_TRACE, "request_bind: "
"added bind from client connid=%lu to upstream connid=%lu "
"as msgid=%d\n",
op->o_client_connid, op->o_upstream_connid, op->o_upstream_msgid );
if ( tavl_insert( &upstream->c_ops, op, operation_upstream_cmp,
avl_dup_error ) ) {
assert(0);
}
upstream->c_state = LLOAD_C_ACTIVE;
CONNECTION_UNLOCK(upstream);
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
ber_free( copy, 0 );
connection_write_cb( -1, 0, upstream );
return 0;
fail:
if ( copy ) {
ber_free( copy, 0 );
}
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
Debug( LDAP_DEBUG_STATS, "request_bind: "
"connid=%lu bind request processing failed, closing\n",
client->c_connid );
return 1;
}
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
......@@ -130,53 +51,16 @@ fail:
* upstream's c_io_mutex.
*/
static int
client_bind_as_vc( LloadOperation *op )
client_bind_as_vc(
LloadOperation *op,
struct berval *binddn,
ber_tag_t tag,
struct berval *auth )
{
LloadConnection *client = op->o_client, *upstream = op->o_upstream;
BerElement *ber, *request, *copy = NULL;
BerValue binddn, auth, mech;
char *msg = "internal error";
int result = LDAP_OTHER;
ber_int_t version;
ber_tag_t tag;
ber_len_t len;
if ( (request = ber_alloc()) == NULL ) {
goto fail;
}
ber_init2( request, &op->o_request, 0 );
tag = ber_scanf( request, "im", &version, &binddn );
if ( tag == LBER_ERROR || version != LDAP_VERSION3 ) {
result = LDAP_PROTOCOL_ERROR;
msg = "version not recognised";
goto fail;
}
copy = ber_dup( request );
if ( !copy ) {
goto fail;
}
tag = ber_skip_element( request, &auth );
if ( tag == LBER_ERROR ) {
result = LDAP_PROTOCOL_ERROR;
msg = "malformed bind request";
goto fail;
}
ber = upstream->c_pendingber;
if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
Debug( LDAP_DEBUG_ANY, "request_bind_as_vc: "
"ber_alloc failed\n" );
goto fail;
}
upstream->c_pendingber = ber;
op->o_upstream_msgid = upstream->c_next_msgid++;
LloadConnection *upstream = op->o_upstream;
CONNECTION_LOCK(upstream);
ber_printf( ber, "t{tit{tst{{tOOtOtO}}}}", LDAP_TAG_MESSAGE,
ber_printf( upstream->c_pendingber, "t{tit{tst{{tOOtOtO}}}}", LDAP_TAG_MESSAGE,
LDAP_TAG_MSGID, op->o_upstream_msgid,
LDAP_REQ_EXTENDED,
LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_VERIFY_CREDENTIALS,
......@@ -185,84 +69,18 @@ client_bind_as_vc( LloadOperation *op )
&binddn, tag, &auth,
LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) );
CONNECTION_UNLOCK(upstream);
tag = ber_peek_tag( copy, &len );
switch ( tag ) {
case LDAP_AUTH_SASL:
ber_get_stringbv( copy, &mech, LBER_BV_NOTERM );
CONNECTION_LOCK(client);
if ( ber_bvcmp( &mech, &client->c_sasl_bind_mech ) ) {
ber_memfree( client->c_sasl_bind_mech.bv_val );
ber_dupbv( &client->c_sasl_bind_mech, &mech );
}
CONNECTION_UNLOCK(client);
/* TODO: extract authzdn from the message */
break;
case LDAP_AUTH_SIMPLE:
CONNECTION_LOCK(client);
if ( !BER_BVISNULL( &client->c_auth ) ) {
ch_free( client->c_auth.bv_val );
}
if ( !BER_BVISEMPTY( &binddn ) ) {
char *ptr;
client->c_auth.bv_len = STRLENOF("dn:") + binddn.bv_len;
client->c_auth.bv_val = ch_malloc( client->c_auth.bv_len + 1 );
ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" );
ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len );
*ptr = '\0';
} else {
BER_BVZERO( &client->c_auth );
}
if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) {
ber_memfree( client->c_sasl_bind_mech.bv_val );
BER_BVZERO( &client->c_sasl_bind_mech );
}
CONNECTION_UNLOCK(client);
break;
default:
result = LDAP_PROTOCOL_ERROR;
msg = "malformed bind request";
goto fail;
}
CONNECTION_LOCK(upstream);
Debug( LDAP_DEBUG_TRACE, "request_bind_as_vc: "
"added bind from client connid=%lu to upstream connid=%lu "
"as VC exop msgid=%d\n",
op->o_client_connid, op->o_upstream_connid, op->o_upstream_msgid );
if ( tavl_insert( &upstream->c_ops, op, operation_upstream_cmp,
avl_dup_error ) ) {
assert(0);
}
CONNECTION_UNLOCK(upstream);
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
ber_free( copy, 0 );
connection_write_cb( -1, 0, upstream );
return 0;
fail:
if ( copy ) {
ber_free( copy, 0 );
}
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
Debug( LDAP_DEBUG_STATS, "request_bind_as_vc: "
"connid=%lu bind request processing failed, closing\n",
client->c_connid );
operation_send_reject( op, result, msg, 1 );
return 1;
}
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
int
request_bind( LloadConnection *client, LloadOperation *op )
{
LloadConnection *upstream;
LloadConnection *upstream = NULL;
BerElement *ber, *copy;
struct berval binddn, auth;
ber_int_t version;
ber_tag_t tag;
int res, rc = LDAP_SUCCESS;
/* protect the Bind operation */
......@@ -274,61 +92,152 @@ request_bind( LloadConnection *client, LloadOperation *op )
client->c_state = LLOAD_C_BINDING;
client->c_type = LLOAD_C_OPEN;
if ( (copy = ber_alloc()) == NULL ) {
goto fail;
}
ber_init2( copy, &op->o_request, 0 );
tag = ber_get_int( copy, &version );
if ( tag == LBER_ERROR ) {
Debug( LDAP_DEBUG_PACKETS, "request_bind: "
"failed to parse version field\n" );
goto fail;
} else if ( version != LDAP_VERSION3 ) {
operation_send_reject_locked(
op, LDAP_PROTOCOL_ERROR, "LDAP version unsupported", 1 );
ber_free( copy, 0 );
return LDAP_SUCCESS;
}
tag = ber_get_stringbv( copy, &binddn, LBER_BV_NOTERM );
if ( tag == LBER_ERROR ) {
Debug( LDAP_DEBUG_PACKETS, "request_bind: "
"failed to parse bind name field\n" );
goto fail;
}
tag = ber_skip_element( copy, &auth );
if ( tag == LDAP_AUTH_SIMPLE ) {
if ( !BER_BVISNULL( &client->c_auth ) ) {
ch_free( client->c_auth.bv_val );
}
if ( !BER_BVISEMPTY( &binddn ) ) {
char *ptr;
client->c_auth.bv_len = STRLENOF("dn:") + binddn.bv_len;
client->c_auth.bv_val = ch_malloc( client->c_auth.bv_len + 1 );
ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" );
ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len );
*ptr = '\0';
} else {
BER_BVZERO( &client->c_auth );
}
if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) {
ber_memfree( client->c_sasl_bind_mech.bv_val );
BER_BVZERO( &client->c_sasl_bind_mech );
}
} else if ( tag == LDAP_AUTH_SASL ) {
operation_send_reject( op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
"no SASL support available yet", 1 );
ber_free( copy, 0 );
return LDAP_SUCCESS;
} else {
goto fail;
}
rc = tavl_insert( &client->c_ops, op, operation_client_cmp, avl_dup_error );
assert( rc == LDAP_SUCCESS );
CONNECTION_UNLOCK_INCREF(client);
upstream = backend_select( op, &res );
if ( !upstream ) {
Debug( LDAP_DEBUG_STATS, "client_bind: "
Debug( LDAP_DEBUG_STATS, "request_bind: "
"connid=%lu, msgid=%d no available connection found\n",
op->o_client_connid, op->o_client_msgid );
operation_send_reject( op, res, "no connections available", 1 );
goto done;
}
ber = upstream->c_pendingber;
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);
CONNECTION_UNLOCK_OR_DESTROY(upstream);
CONNECTION_LOCK_DECREF(client);
op->o_client_refcnt--;
operation_destroy_from_client( op );
return rc;
goto fail;
}
upstream->c_pendingber = ber;
CONNECTION_LOCK(upstream);
op->o_upstream = upstream;
op->o_upstream_connid = upstream->c_connid;
op->o_upstream_msgid = upstream->c_next_msgid++;
Debug( LDAP_DEBUG_TRACE, "request_bind: "
"added bind from client connid=%lu to upstream connid=%lu "
"as msgid=%d\n",
op->o_client_connid, op->o_upstream_connid, op->o_upstream_msgid );
if ( tavl_insert( &upstream->c_ops, op, operation_upstream_cmp,
avl_dup_error ) ) {
assert(0);
}
upstream->c_state = LLOAD_C_BINDING;
CONNECTION_UNLOCK(upstream);
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
if ( lload_features & LLOAD_FEATURE_VC ) {
rc = client_bind_as_vc( op );
rc = client_bind_as_vc( op, &binddn, tag, &auth );
} else
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
{
rc = client_bind( op );
rc = client_bind( op, &binddn, tag, &auth );
}
CONNECTION_LOCK_DECREF(upstream);
CONNECTION_UNLOCK_OR_DESTROY(upstream);
done:
if ( rc == LDAP_SUCCESS ) {
CONNECTION_LOCK(client);
if ( upstream ) {
ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
}
CONNECTION_LOCK_DECREF(client);
if ( rc ) {
if ( !--op->o_client_refcnt || !upstream ) {
operation_destroy_from_client( op );
if ( client->c_state == LLOAD_C_BINDING ) {
client->c_state = LLOAD_C_READY;
client->c_type = LLOAD_C_OPEN;
if ( !BER_BVISNULL( &client->c_auth ) ) {
ch_free( client->c_auth.bv_val );
BER_BVZERO( &client->c_auth );
}
if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) {
ber_memfree( client->c_sasl_bind_mech.bv_val );
BER_BVZERO( &client->c_sasl_bind_mech );
}
}
}
CONNECTION_UNLOCK(client);
if ( upstream ) {
connection_write_cb( -1, 0, upstream );
CONNECTION_LOCK_DECREF(upstream);
CONNECTION_UNLOCK_OR_DESTROY(upstream);
}
CONNECTION_LOCK_DECREF(client);
} else {
fail:
rc = -1;
CONNECTION_LOCK_DECREF(client);
op->o_client_refcnt--;
operation_destroy_from_client( op );
CONNECTION_DESTROY(client);
return -1;
}
if ( !--op->o_client_refcnt ) {
operation_destroy_from_client( op );
if ( client->c_state == LLOAD_C_BINDING ) {
client->c_state = LLOAD_C_READY;
client->c_type = LLOAD_C_OPEN;
if ( !BER_BVISNULL( &client->c_auth ) ) {
ber_memfree( client->c_auth.bv_val );
BER_BVZERO( &client->c_auth );
}
if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) {
ber_memfree( client->c_sasl_bind_mech.bv_val );
BER_BVZERO( &client->c_sasl_bind_mech );
}
}
}
ber_free( copy, 0 );
return rc;
}
......
Supports Markdown
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