]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
Refactor request parsing and sending.
authorOndřej Kuzník <ondra@mistotebe.net>
Wed, 13 Dec 2017 17:34:59 +0000 (17:34 +0000)
committerOndřej Kuzník <okuznik@symas.com>
Tue, 17 Nov 2020 17:58:14 +0000 (17:58 +0000)
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

index 3b6bb225a9e90b729b09a9e28dfc80fbede753e3..8f24b5a6989f57747618928e2a6f02c1f7cbe01d 100644 (file)
  * 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;
 }