]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
Resolve authzid after a successful auth
authorOndřej Kuzník <ondra@mistotebe.net>
Thu, 18 Jan 2018 14:46:24 +0000 (14:46 +0000)
committerOndřej Kuzník <okuznik@symas.com>
Tue, 17 Nov 2020 17:58:14 +0000 (17:58 +0000)
servers/lloadd/bind.c
servers/lloadd/proto-lload.h
servers/lloadd/upstream.c

index 402564a2f443019967817d04c2305030b2d6a529..6565d33c47f3111d0510c01aa090877fb99ea1a8 100644 (file)
@@ -476,6 +476,86 @@ fail:
     return rc;
 }
 
+/*
+ * Remember the response, but first ask the server what
+ * authorization identity has been negotiated.
+ *
+ * Also, this request will fail if the server thinks a SASL
+ * confidentiality/integrity layer has been negotiated so we catch
+ * it early and no other clients are affected.
+ */
+int
+finish_sasl_bind(
+        LloadConnection *upstream,
+        LloadOperation *op,
+        BerElement *ber )
+{
+    LloadConnection *client = op->o_client;
+    BerElement *output;
+    LloadOperation *removed;
+    ber_int_t msgid;
+    int rc;
+
+    if ( !(lload_features & LLOAD_FEATURE_PROXYAUTHZ) ) {
+        Debug( LDAP_DEBUG_TRACE, "finish_sasl_bind: "
+                "connid=%lu not configured to do proxyauthz, making no "
+                "attempt to resolve final authzid name\n",
+                op->o_client_connid );
+        CONNECTION_UNLOCK(upstream);
+        return forward_final_response( client, op, ber );
+    }
+
+    removed = tavl_delete( &upstream->c_ops, op, operation_upstream_cmp );
+    if ( !removed ) {
+        assert( upstream->c_state != LLOAD_C_BINDING );
+        /* FIXME: has client replaced this bind since? */
+        assert(0);
+
+        operation_destroy_from_upstream( op );
+    }
+    assert( removed == op && upstream->c_state == LLOAD_C_BINDING );
+
+    CONNECTION_UNLOCK(upstream);
+
+    Debug( LDAP_DEBUG_TRACE, "finish_sasl_bind: "
+            "SASL exchange in lieu of client connid=%lu to upstream "
+            "connid=%lu finished, resolving final authzid name\n",
+            op->o_client_connid, op->o_upstream_connid );
+
+    ldap_pvt_thread_mutex_lock( &upstream->c_io_mutex );
+    output = upstream->c_pendingber;
+    if ( output == NULL && (output = ber_alloc()) == NULL ) {
+        ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
+        return -1;
+    }
+    upstream->c_pendingber = output;
+
+    msgid = upstream->c_next_msgid++;
+    ber_printf( output, "t{tit{ts}}", LDAP_TAG_MESSAGE,
+            LDAP_TAG_MSGID, msgid,
+            LDAP_REQ_EXTENDED,
+            LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_WHO_AM_I );
+
+    /* Make sure noone flushes the buffer before we re-insert the operation */
+    CONNECTION_LOCK(upstream);
+    ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
+
+    op->o_upstream_msgid = msgid;
+
+    /* remember the response for later */
+    ber_free( op->o_ber, 1 );
+    op->o_ber = ber;
+
+    rc = tavl_insert(
+            &upstream->c_ops, op, operation_upstream_cmp, avl_dup_error );
+    assert( rc == LDAP_SUCCESS );
+
+    CONNECTION_UNLOCK(upstream);
+
+    connection_write_cb( -1, 0, upstream );
+    return LDAP_SUCCESS;
+}
+
 int
 handle_bind_response(
         LloadConnection *client,
@@ -515,13 +595,20 @@ handle_bind_response(
 
     CONNECTION_LOCK(upstream);
     if ( result != LDAP_SASL_BIND_IN_PROGRESS ) {
+        int sasl_finished = 0;
         if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) {
+            sasl_finished = 1;
             ber_memfree( upstream->c_sasl_bind_mech.bv_val );
             BER_BVZERO( &upstream->c_sasl_bind_mech );
         }
 
-        upstream->c_state = LLOAD_C_READY;
+        assert( op->o_client_msgid && op->o_upstream_msgid );
         op->o_pin_id = 0;
+
+        if ( sasl_finished && result == LDAP_SUCCESS ) {
+            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;
@@ -584,6 +671,99 @@ done:
     return forward_final_response( client, op, ber );
 }
 
+int
+handle_whoami_response(
+        LloadConnection *client,
+        LloadOperation *op,
+        BerElement *ber )
+{
+    LloadConnection *upstream = op->o_upstream;
+    BerValue matched, diagmsg;
+    BerElement *saved_response = op->o_ber;
+    LloadOperation *removed;
+    ber_int_t result;
+    ber_tag_t tag;
+    ber_len_t len;
+
+    Debug( LDAP_DEBUG_TRACE, "handle_whoami_response: "
+            "connid=%ld received whoami response in lieu of connid=%ld\n",
+            upstream->c_connid, client->c_connid );
+
+    tag = ber_scanf( ber, "{emm" /* "}" */,
+            &result, &matched, &diagmsg );
+    if ( tag == LBER_ERROR ) {
+        operation_send_reject( op, LDAP_OTHER, "upstream protocol error", 0 );
+        return -1;
+    }
+
+    CONNECTION_LOCK_DECREF(upstream);
+    if ( result == LDAP_PROTOCOL_ERROR ) {
+        LloadBackend *b;
+
+        b = (LloadBackend *)upstream->c_private;
+        Debug( LDAP_DEBUG_ANY, "handle_whoami_response: "
+                "Who Am I? extended operation not supported on backend %s, "
+                "proxyauthz with clients that do SASL binds will not work "
+                "msg=%s!\n",
+                b->b_uri.bv_val, diagmsg.bv_val );
+        CONNECTION_UNLOCK_INCREF(upstream);
+        operation_send_reject( op, LDAP_OTHER, "upstream protocol error", 0 );
+        return -1;
+    }
+    upstream->c_state = LLOAD_C_READY;
+
+    CONNECTION_UNLOCK_INCREF(upstream);
+
+    tag = ber_peek_tag( ber, &len );
+
+    CONNECTION_LOCK_DECREF(client);
+
+    assert( client->c_state == LLOAD_C_BINDING &&
+            BER_BVISNULL( &client->c_auth ) );
+    if ( !BER_BVISNULL( &client->c_auth ) ) {
+        ber_memfree( client->c_auth.bv_val );
+        BER_BVZERO( &client->c_auth );
+    }
+
+    if ( tag == LDAP_TAG_EXOP_RES_VALUE ) {
+        tag = ber_scanf( ber, "o", &client->c_auth );
+        if ( tag == LBER_ERROR ) {
+            operation_send_reject_locked(
+                    op, LDAP_OTHER, "upstream protocol error", 0 );
+            CONNECTION_DESTROY(client);
+            return -1;
+        }
+    }
+
+    removed = tavl_delete( &client->c_ops, op, operation_client_cmp );
+    assert( !removed || op == removed );
+
+    Debug( LDAP_DEBUG_TRACE, "handle_whoami_response: "
+            "connid=%ld new authid=%s\n",
+            client->c_connid, client->c_auth.bv_val );
+
+    if ( client->c_state == LLOAD_C_BINDING ) {
+        op->o_client = NULL;
+        client->c_state = LLOAD_C_READY;
+        client->c_type = LLOAD_C_OPEN;
+        client->c_pin_id = 0;
+        if ( !BER_BVISNULL( &client->c_auth ) &&
+                !ber_bvstrcasecmp( &client->c_auth, &lloadd_identity ) ) {
+            client->c_type = LLOAD_C_PRIVILEGED;
+        }
+        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_INCREF(client);
+
+    /* defer the disposal of ber to operation_destroy_* */
+    op->o_ber = ber;
+    return forward_final_response( client, op, saved_response );
+}
+
 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
 int
 handle_vc_bind_response(
index ebad0ada33c8da390ecccdaca6afff6482c50ae5..6efcac44a757f6d91cc3489c6b8166859fbe696b 100644 (file)
@@ -51,6 +51,7 @@ LDAP_SLAPD_F (void) backends_destroy( void );
  */
 LDAP_SLAPD_F (int) request_bind( LloadConnection *c, LloadOperation *op );
 LDAP_SLAPD_F (int) handle_bind_response( LloadConnection *client, LloadOperation *op, BerElement *ber );
+LDAP_SLAPD_F (int) handle_whoami_response( LloadConnection *client, LloadOperation *op, BerElement *ber );
 LDAP_SLAPD_F (int) handle_vc_bind_response( LloadConnection *client, LloadOperation *op, BerElement *ber );
 
 /*
index 96240ad7612d260e9979147b21783ed061717269..7510e80200781a0552bde49b46027274bbecf177 100644 (file)
@@ -190,11 +190,16 @@ handle_one_response( LloadConnection *c )
                 handler = handle_bind_response;
                 break;
             case LDAP_RES_EXTENDED:
-#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
                 if ( op->o_tag == LDAP_REQ_BIND ) {
-                    handler = handle_vc_bind_response;
-                }
+#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
+                    if ( lload_features & LLOAD_FEATURE_VC ) {
+                        handler = handle_vc_bind_response;
+                    } else
 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
+                    {
+                        handler = handle_whoami_response;
+                    }
+                }
                 break;
         }
         if ( !handler ) {