From 21a22d1bf14c6c5b1d708b3c983ed0b8bc7ccda1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 13 Dec 2017 17:34:59 +0000 Subject: [PATCH] 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. --- servers/lloadd/bind.c | 397 ++++++++++++++++-------------------------- 1 file changed, 153 insertions(+), 244 deletions(-) diff --git a/servers/lloadd/bind.c b/servers/lloadd/bind.c index 3b6bb225a9..8f24b5a698 100644 --- a/servers/lloadd/bind.c +++ b/servers/lloadd/bind.c @@ -29,21 +29,68 @@ * 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; + LloadConnection *upstream = op->o_upstream; - 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; + 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 ) ); + + return 0; +} + +#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS +/* + * On entering the function, we've put a reference on both connections and hold + * upstream's c_io_mutex. + */ +static int +client_bind_as_vc( + LloadOperation *op, + struct berval *binddn, + ber_tag_t tag, + struct berval *auth ) +{ + LloadConnection *upstream = op->o_upstream; + + CONNECTION_LOCK(upstream); + 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, + LDAP_TAG_EXOP_REQ_VALUE, + LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, BER_BV_OPTIONAL( &upstream->c_vc_cookie ), + &binddn, tag, &auth, + LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) ); + CONNECTION_UNLOCK(upstream); + return 0; +} +#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ + +int +request_bind( LloadConnection *client, LloadOperation *op ) +{ + 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 */ + op->o_client_refcnt++; + tavl_delete( &client->c_ops, op, operation_client_cmp ); + + client_reset( client ); + + client->c_state = LLOAD_C_BINDING; + client->c_type = LLOAD_C_OPEN; if ( (copy = ber_alloc()) == NULL ) { goto fail; @@ -56,11 +103,10 @@ client_bind( LloadOperation *op ) "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( + operation_send_reject_locked( op, LDAP_PROTOCOL_ERROR, "LDAP version unsupported", 1 ); ber_free( copy, 0 ); - return 0; + return LDAP_SUCCESS; } tag = ber_get_stringbv( copy, &binddn, LBER_BV_NOTERM ); @@ -70,32 +116,67 @@ client_bind( LloadOperation *op ) goto fail; } - CONNECTION_LOCK(client); - if ( !BER_BVISNULL( &client->c_auth ) ) { - ch_free( client->c_auth.bv_val ); - } + 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 ); - 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 ); + } - ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" ); - ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len ); - *ptr = '\0'; + 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 { - BER_BVZERO( &client->c_auth ); + goto fail; } - CONNECTION_UNLOCK(client); + + 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, "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); + 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++; - ber_printf( ber, "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", @@ -104,231 +185,59 @@ client_bind( LloadOperation *op ) avl_dup_error ) ) { assert(0); } - upstream->c_state = LLOAD_C_ACTIVE; + upstream->c_state = LLOAD_C_BINDING; 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 -/* - * On entering the function, we've put a reference on both connections and hold - * upstream's c_io_mutex. - */ -static int -client_bind_as_vc( LloadOperation *op ) -{ - 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++; - - CONNECTION_LOCK(upstream); - ber_printf( ber, "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, - LDAP_TAG_EXOP_REQ_VALUE, - LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, BER_BV_OPTIONAL( &upstream->c_vc_cookie ), - &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; - int res, rc = LDAP_SUCCESS; - - /* protect the Bind operation */ - op->o_client_refcnt++; - tavl_delete( &client->c_ops, op, operation_client_cmp ); - - client_reset( client ); - - client->c_state = LLOAD_C_BINDING; - client->c_type = LLOAD_C_OPEN; - - 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: " - "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 ); - CONNECTION_LOCK_DECREF(client); - op->o_client_refcnt--; - operation_destroy_from_client( op ); - return rc; - } - - op->o_upstream = upstream; - op->o_upstream_connid = upstream->c_connid; - #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; }