s4:libcli/ldap: add tls channel binding support for ldap_bind_sasl()
authorStefan Metzmacher <metze@samba.org>
Thu, 28 Sep 2023 15:11:03 +0000 (17:11 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Apr 2024 23:50:34 +0000 (23:50 +0000)
We still allow 'ldap_testing:tls_channel_bindings = no' and
'ldap_testing:channel_bound = no' for testing
the old behavior in order to have expected failures in our tests.

And we have 'ldap_testing:forced_channel_binding = somestring'
in order to force invalid bindings.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15621

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/libcli/ldap/ldap_bind.c

index e1a37a391c5b4b164c3111dea7e91a032c27b60b..b00329c9fa43fb6e5037f1b1a2b593740f4ffd39 100644 (file)
@@ -217,6 +217,17 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
        uint32_t old_gensec_features;
        unsigned int logon_retries = 0;
        size_t queue_length;
+       const DATA_BLOB *tls_cb = NULL;
+       bool use_channel_bound = lpcfg_parm_bool(lp_ctx,
+                                                 NULL,
+                                                 "ldap_testing",
+                                                 "channel_bound",
+                                                 true);
+       const char *forced_channel_binding = lpcfg_parm_string(lp_ctx,
+                                                 NULL,
+                                                 "ldap_testing",
+                                                 "forced_channel_binding");
+       DATA_BLOB forced_cb = data_blob_string_const(forced_channel_binding);
 
        if (conn->sockets.active == NULL) {
                status = NT_STATUS_CONNECTION_DISCONNECTED;
@@ -247,11 +258,25 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
        gensec_init();
 
        if (conn->sockets.active == conn->sockets.tls) {
+               /*
+                * allow this for testing the old code:
+                * ldap_testing:no_tls_channel_bindings = no
+                */
+               bool use_tls_cb = lpcfg_parm_bool(lp_ctx,
+                                                 NULL,
+                                                 "ldap_testing",
+                                                 "tls_channel_bindings",
+                                                 true);
+
                /*
                 * require Kerberos SIGN/SEAL only if we don't use SSL
                 * Windows seem not to like double encryption
                 */
                wrap_flags = 0;
+
+               if (use_tls_cb) {
+                       tls_cb = tstream_tls_channel_bindings(conn->sockets.tls);
+               }
        } else if (cli_credentials_is_anonymous(creds)) {
                /*
                 * anonymous isn't protected
@@ -261,6 +286,10 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
                wrap_flags = lpcfg_client_ldap_sasl_wrapping(lp_ctx);
        }
 
+       if (forced_cb.length != 0) {
+              tls_cb = &forced_cb;
+       }
+
 try_logon_again:
        /*
          we loop back here on a logon failure, and re-create the
@@ -306,6 +335,10 @@ try_logon_again:
                gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
        }
 
+       if (!use_channel_bound) {
+               gensec_want_feature(conn->gensec, GENSEC_FEATURE_CB_OPTIONAL);
+       }
+
        /*
         * This is an indication for the NTLMSSP backend to
         * also encrypt when only GENSEC_FEATURE_SIGN is requested
@@ -329,6 +362,26 @@ try_logon_again:
                goto failed;
        }
 
+       if (tls_cb != NULL) {
+               uint32_t initiator_addrtype = 0;
+               const DATA_BLOB *initiator_address = NULL;
+               uint32_t acceptor_addrtype = 0;
+               const DATA_BLOB *acceptor_address = NULL;
+               const DATA_BLOB *application_data = tls_cb;
+
+               status = gensec_set_channel_bindings(conn->gensec,
+                                                    initiator_addrtype,
+                                                    initiator_address,
+                                                    acceptor_addrtype,
+                                                    acceptor_address,
+                                                    application_data);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DBG_WARNING("Failed to set GENSEC channel bindings: %s\n",
+                                   nt_errstr(status));
+                       goto failed;
+               }
+       }
+
        status = gensec_start_mech_by_sasl_name(conn->gensec, sasl_mech);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("gensec_start_mech_by_sasl_name(%s): %s\n",