s4:ldap_server: add support for tls channel bindings
authorStefan Metzmacher <metze@samba.org>
Tue, 23 Jan 2024 13:20:24 +0000 (14:20 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Apr 2024 23:50:34 +0000 (23:50 +0000)
ldap server require strong auth = allow_sasl_over_tls
is now an alias for 'allow_sasl_without_tls_channel_bindings'
and should be avoided and changed to 'yes' or
'allow_sasl_without_tls_channel_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>
docs-xml/smbdotconf/ldap/ldapserverrequirestrongauth.xml
lib/param/loadparm.h
lib/param/param_table.c
python/samba/netcmd/testparm.py
selftest/target/Samba4.pm
source3/utils/testparm.c
source4/ldap_server/ldap_bind.c
source4/ldap_server/ldap_server.c

index 02bdd8114919e89692d05a4b1643f2f5bab016d7..18f8903dcaab64a1752050778d7932ca4f0d598c 100644 (file)
@@ -7,20 +7,44 @@
        <para>
        The <smbconfoption name="ldap server require strong auth"/> defines whether
        the ldap server requires ldap traffic to be signed or signed and encrypted (sealed).
-       Possible values are <emphasis>no</emphasis>, <emphasis>allow_sasl_over_tls</emphasis>
+       Possible values are <emphasis>no</emphasis>,
+       <emphasis>allow_sasl_without_tls_channel_bindings</emphasis>
        and <emphasis>yes</emphasis>.
        </para>
 
+       <para>Windows has <emphasis>LdapEnforceChannelBinding</emphasis> under
+       <emphasis>HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters\</emphasis>.
+       </para>
+
        <para>A value of <emphasis>no</emphasis> allows simple and sasl binds over
-       all transports.</para>
+       all transports. This matches LdapEnforceChannelBinding=0.</para>
+
+       <para>A value of <emphasis>allow_sasl_without_tls_channel_bindings</emphasis>
+       allows simple and sasl binds (without sign or seal) over TLS encrypted connections.
+       Missing tls channel bindings are ignored, so only use this if a value of
+       <emphasis>yes</emphasis> is not possible.
+       Unencrypted connections only allow sasl binds with sign or seal.
+       This matches LdapEnforceChannelBinding=1.
+       </para>
 
-       <para>A value of <emphasis>allow_sasl_over_tls</emphasis> allows simple and sasl binds
-       (without sign or seal) over TLS encrypted connections. Unencrypted connections only
-       allow sasl binds with sign or seal.</para>
+       <para>Before support for tls channel bindings existed in Samba,
+       a value of <emphasis>allow_sasl_over_tls</emphasis> was possible in order
+       to allow sasl binds without tls channel bindings. This now misleading
+       as a value of <emphasis>yes</emphasis> will now allow sasl binds
+       with tls channel bindings. Configurations should be changed to
+       <emphasis>yes</emphasis> instead or
+       <emphasis>allow_sasl_without_tls_channel_bindings</emphasis>
+       if really required. Currently <emphasis>allow_sasl_over_tls</emphasis>
+       is just an alias of <emphasis>allow_sasl_without_tls_channel_bindings</emphasis>,
+       but it will be removed in future versions.
+       </para>
 
        <para>A value of <emphasis>yes</emphasis> allows only simple binds
-       over TLS encrypted connections. Unencrypted connections only
-       allow sasl binds with sign or seal.</para>
+       and sasl binds with correct tls channel bindings
+       over TLS encrypted connections. sasl binds without tls channel bindings
+       are not allowed. Unencrypted connections only
+       allow sasl binds with sign or seal. This matches LdapEnforceChannelBinding=2.
+       </para>
 </description>
 <value type="default">yes</value>
 </samba:parameter>
index 0bf4c173652c2ac0bac9aacddb2d0f370c878e0b..7e9e5d2da3f8f5f4dab0798aacca710f86423b14 100644 (file)
@@ -206,6 +206,7 @@ enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,
 enum ldap_server_require_strong_auth {
        LDAP_SERVER_REQUIRE_STRONG_AUTH_NO,
        LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS,
+       LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_WITHOUT_TLS_CB,
        LDAP_SERVER_REQUIRE_STRONG_AUTH_YES,
 };
 
index ce591560ba832a3f3c19e0e25e6b16e26b0a3843..8db4c381e41278f8a5e51dbb95c0b5506940217c 100644 (file)
@@ -318,6 +318,8 @@ static const struct enum_list enum_ldap_server_require_strong_auth_vals[] = {
        { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "0" },
        { LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS,
          "allow_sasl_over_tls" },
+       { LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_WITHOUT_TLS_CB,
+         "allow_sasl_without_tls_channel_bindings" },
        { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "Yes" },
        { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "True" },
        { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "1" },
index 41dbb4bd62362dc93a9fc2220ecb5830ce6db157..a419ddf126064de8bb6da2660f8dc08781aabee6 100644 (file)
@@ -183,6 +183,16 @@ class cmd_testparm(Command):
                             "When acting as Active Directory domain controller, " +
                             entry + " should be in vfs objects.")
 
+        strong_auth = lp.get("ldap server require strong auth")
+        if strong_auth == "allow_sasl_over_tls":
+            logger.warning(
+                "WARNING: You have not configured "
+                "'ldap server require strong auth = "
+                "allow_sasl_over_tls'.\n"
+                "Please change to 'yes' (preferred) or "
+                "'allow_sasl_without_tls_channel_bindings' "
+                "(if really needed).")
+
         return valid
 
     def allow_access(self, deny_list, allow_list, cname, caddr):
index 48a78b2c8d2950f6931228050625b32b14c312ad..f52d6740c6e523d81a5c8d78bf7f99421d01a2a9 100755 (executable)
@@ -1625,7 +1625,7 @@ sub provision_ad_dc_ntvfs($$$)
        print "PROVISIONING AD DC (NTVFS)...\n";
         my $extra_conf_options = "netbios aliases = localDC1-a
         server services = +winbind -winbindd
-       ldap server require strong auth = allow_sasl_over_tls
+       ldap server require strong auth = allow_sasl_without_tls_channel_bindings
        raw NTLMv2 auth = yes
        lsa over netlogon = yes
         rpc server port = 1027
index fd90e8d734a8842bc312fdc251472abaabf6e1fe..34bce413f82f70900cf5e08459c166d19c7779b3 100644 (file)
@@ -615,6 +615,18 @@ static int do_global_checks(void)
                ret = 1;
        }
 
+       if (lp_ldap_server_require_strong_auth() ==
+           LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS)
+       {
+               fprintf(stderr,
+                       "WARNING: You have not configured "
+                       "'ldap server require strong auth = "
+                       "allow_sasl_over_tls'.\n"
+                       "Please change to 'yes' (preferred) or "
+                       "'allow_sasl_without_tls_channel_bindings' "
+                       "(if really needed)\n\n");
+       }
+
        if (lp_server_schannel() != true) { /* can be 'auto' */
                fprintf(stderr,
                        "WARNING: You have not configured "
index d592d472c06d3f0cc7fb789025e4c5cbb4751e4f..65e252edb702a4a1ef981933031ff61d766440ea 100644 (file)
@@ -27,6 +27,7 @@
 #include "dsdb/samdb/samdb.h"
 #include "auth/gensec/gensec.h"
 #include "auth/gensec/gensec_tstream.h"
+#include "lib/tls/tls.h"
 #include "param/param.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "lib/util/time_basic.h"
@@ -359,6 +360,49 @@ static NTSTATUS ldapsrv_setup_gensec(struct ldapsrv_connection *conn,
        gensec_want_feature(gensec_security, GENSEC_FEATURE_LDAP_STYLE);
 
        if (conn->sockets.active == conn->sockets.tls) {
+               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 =
+                       tstream_tls_channel_bindings(conn->sockets.tls);
+
+               status = gensec_set_channel_bindings(gensec_security,
+                                                    initiator_addrtype,
+                                                    initiator_address,
+                                                    acceptor_addrtype,
+                                                    acceptor_address,
+                                                    application_data);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+
+               /*
+                * By default channel bindings are required,
+                * so we only set GENSEC_FEATURE_CB_OPTIONAL
+                * for the legacy option:
+                *
+                * ldap server require strong auth = no
+                * or
+                * ldap server require strong auth =
+                *    allow_sasl_without_tls_channel_bindings
+                *
+                * And this as an alias to cope with existing smb.conf
+                * files:
+                *
+                * ldap server require strong auth = allow_sasl_over_tls
+                */
+               switch (conn->require_strong_auth) {
+               case LDAP_SERVER_REQUIRE_STRONG_AUTH_NO:
+               case LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS:
+               case LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_WITHOUT_TLS_CB:
+                       gensec_want_feature(gensec_security,
+                                           GENSEC_FEATURE_CB_OPTIONAL);
+                       break;
+               default:
+                       break;
+               }
+
                gensec_want_feature(gensec_security, GENSEC_FEATURE_LDAPS_TRANSPORT);
        }
 
@@ -496,6 +540,14 @@ static void ldapsrv_BindSASL_done(struct tevent_req *subreq)
                goto do_reply;
        }
 
+       if (NT_STATUS_EQUAL(status, NT_STATUS_BAD_BINDINGS)) {
+               result = LDAP_INVALID_CREDENTIALS;
+               errstr = ldapsrv_bind_error_msg(reply,
+                                               HRES_SEC_E_BAD_BINDINGS,
+                                               0x0C090711,
+                                               status);
+               goto do_reply;
+       }
        if (!NT_STATUS_IS_OK(status)) {
                status = nt_status_squash(status);
                result = LDAP_INVALID_CREDENTIALS;
@@ -539,17 +591,11 @@ static void ldapsrv_BindSASL_done(struct tevent_req *subreq)
                case LDAP_SERVER_REQUIRE_STRONG_AUTH_NO:
                        break;
                case LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS:
+               case LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_WITHOUT_TLS_CB:
+               case LDAP_SERVER_REQUIRE_STRONG_AUTH_YES:
                        if (call->conn->sockets.active == call->conn->sockets.tls) {
                                break;
                        }
-                       status = NT_STATUS_NETWORK_ACCESS_DENIED;
-                       result = LDAP_STRONG_AUTH_REQUIRED;
-                       errstr = talloc_asprintf(reply,
-                                       "SASL:[%s]: not allowed if TLS is used.",
-                                        req->creds.SASL.mechanism);
-                       goto do_reply;
-
-               case LDAP_SERVER_REQUIRE_STRONG_AUTH_YES:
                        status = NT_STATUS_NETWORK_ACCESS_DENIED;
                        result = LDAP_STRONG_AUTH_REQUIRED;
                        errstr = talloc_asprintf(reply,
index 497d0dbc9a11f0406f97742d0ec1533b81b4cee8..90316fd6b68cd2578cd57e07235775fda0484497 100644 (file)
@@ -378,6 +378,17 @@ static void ldapsrv_accept(struct stream_connection *c,
                conn->require_strong_auth = lpcfg_ldap_server_require_strong_auth(conn->lp_ctx);
        }
 
+       if (conn->require_strong_auth ==
+           LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS)
+       {
+               D_ERR("WARNING: You have not configured "
+                     "'ldap server require strong auth = "
+                     "allow_sasl_over_tls'.\n"
+                     "Please change to 'yes' (preferred and default) or "
+                     "'allow_sasl_without_tls_channel_bindings' "
+                     "(if really needed)\n\n");
+       }
+
        ret = ldapsrv_backend_Init(conn, &errstring);
        if (ret != LDB_SUCCESS) {
                char *reason = talloc_asprintf(conn,