]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
tests/krb5: Handle NT hashes being disabled
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Tue, 24 May 2022 07:11:22 +0000 (19:11 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 5 May 2023 02:54:30 +0000 (02:54 +0000)
If NT hashes are disabled, we should not expect the RC4 enctype to be
available for non-computer accounts.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/tests/krb5/as_req_tests.py
python/samba/tests/krb5/group_tests.py
python/samba/tests/krb5/kdc_base_test.py
python/samba/tests/krb5/lockout_tests.py
python/samba/tests/krb5/protected_users_tests.py
python/samba/tests/krb5/raw_testcase.py
python/samba/tests/krb5/spn_tests.py

index c491ea6dce1ce074ea804bd052f32380a42567b2..e8712b5bf8aad62b1b712fa3e067b3c8992c721b 100755 (executable)
@@ -75,7 +75,7 @@ class AsReqBaseTest(KDCBaseTest):
             till = self.get_KerberosTime(offset=36000)
 
         if etypes is None:
-            etypes = self.get_default_enctypes()
+            etypes = self.get_default_enctypes(client_creds)
         if kdc_options is None:
             kdc_options = krb5_asn1.KDCOptions('forwardable')
         if expected_error is not None:
@@ -194,7 +194,7 @@ class AsReqKerberosTests(AsReqBaseTest):
         expected_salt = client_creds.get_salt()
 
         if any(etype in initial_etypes
-               for etype in self.get_default_enctypes()):
+               for etype in self.get_default_enctypes(client_creds)):
             expected_error_mode = KDC_ERR_PREAUTH_REQUIRED
         else:
             expected_error_mode = KDC_ERR_ETYPE_NOSUPP
index 9f9f1e60c8954f18d750ab865e69911339981593..c83e4178fa52241fad5ae02717040e14f754e20d 100755 (executable)
@@ -1871,7 +1871,7 @@ class GroupTests(KDCBaseTest):
         till = self.get_KerberosTime(offset=36000)
         kdc_options = '0'
 
-        etypes = self.get_default_enctypes()
+        etypes = self.get_default_enctypes(user_creds)
 
         # Perform an AS-REQ with the user account.
         as_rep, kdc_exchange_dict = self._test_as_exchange(
index ba41a6ba688d04ac4035413b435ebb9997234c36..f947d45428d44593ce3ad819ec968e8f61fc2ecf 100644 (file)
@@ -426,7 +426,9 @@ class KDCBaseTest(RawKerberosTest):
 
         return self._functional_level
 
-    def get_default_enctypes(self):
+    def get_default_enctypes(self, creds):
+        self.assertIsNotNone(creds, 'expected client creds to be passed in')
+
         functional_level = self.get_domain_functional_level()
 
         default_enctypes = []
@@ -436,8 +438,8 @@ class KDCBaseTest(RawKerberosTest):
             default_enctypes.append(kcrypto.Enctype.AES256)
             default_enctypes.append(kcrypto.Enctype.AES128)
 
-        # RC4 should always be supported
-        default_enctypes.append(kcrypto.Enctype.RC4)
+        if self.expect_nt_hash or creds.get_workstation():
+            default_enctypes.append(kcrypto.Enctype.RC4)
 
         return default_enctypes
 
@@ -956,10 +958,12 @@ class KDCBaseTest(RawKerberosTest):
 
         return bind, identifier, attributes
 
-    def get_keys(self, dn, expected_etypes=None):
+    def get_keys(self, creds, expected_etypes=None):
         admin_creds = self.get_admin_creds()
         samdb = self.get_samdb()
 
+        dn = creds.get_dn()
+
         bind, identifier, attributes = self.get_secrets(
             str(dn),
             destination_dsa_guid=misc.GUID(samdb.get_ntds_GUID()),
@@ -998,7 +1002,7 @@ class KDCBaseTest(RawKerberosTest):
                     keys[kcrypto.Enctype.RC4] = pwd.hex()
 
         if expected_etypes is None:
-            expected_etypes = self.get_default_enctypes()
+            expected_etypes = self.get_default_enctypes(creds)
 
         self.assertCountEqual(expected_etypes, keys)
 
@@ -1044,7 +1048,7 @@ class KDCBaseTest(RawKerberosTest):
                                    fast_support=False,
                                    claims_support=False,
                                    compound_id_support=False):
-        default_enctypes = self.get_default_enctypes()
+        default_enctypes = self.get_default_enctypes(creds)
         supported_enctypes = KerberosCredentials.etypes_to_bits(
             default_enctypes)
 
@@ -1657,7 +1661,7 @@ class KDCBaseTest(RawKerberosTest):
         expected_etypes = None
         if force_nt4_hash:
             expected_etypes = {kcrypto.Enctype.RC4}
-        keys = self.get_keys(dn, expected_etypes=expected_etypes)
+        keys = self.get_keys(creds, expected_etypes=expected_etypes)
         self.creds_set_keys(creds, keys)
 
         # Handle secret replication to the RODC.
@@ -1841,7 +1845,7 @@ class KDCBaseTest(RawKerberosTest):
             creds.set_kvno(rodc_kvno)
             creds.set_dn(krbtgt_dn)
 
-            keys = self.get_keys(krbtgt_dn)
+            keys = self.get_keys(creds)
             self.creds_set_keys(creds, keys)
 
             # The RODC krbtgt account should support the default enctypes,
@@ -1894,7 +1898,7 @@ class KDCBaseTest(RawKerberosTest):
             creds.set_kvno(rodc_kvno)
             creds.set_dn(dn)
 
-            keys = self.get_keys(dn)
+            keys = self.get_keys(creds)
             self.creds_set_keys(creds, keys)
 
             if self.get_domain_functional_level() >= DS_DOMAIN_FUNCTION_2008:
@@ -1945,7 +1949,7 @@ class KDCBaseTest(RawKerberosTest):
             creds.set_kvno(kvno)
             creds.set_dn(dn)
 
-            keys = self.get_keys(dn)
+            keys = self.get_keys(creds)
             self.creds_set_keys(creds, keys)
 
             # The krbtgt account should support the default enctypes, although
@@ -1996,7 +2000,7 @@ class KDCBaseTest(RawKerberosTest):
             creds.set_workstation(username[:-1])
             creds.set_dn(dn)
 
-            keys = self.get_keys(dn)
+            keys = self.get_keys(creds)
             self.creds_set_keys(creds, keys)
 
             if self.get_domain_functional_level() >= DS_DOMAIN_FUNCTION_2008:
@@ -2046,7 +2050,7 @@ class KDCBaseTest(RawKerberosTest):
             creds.set_kvno(kvno)
             creds.set_dn(dn)
 
-            keys = self.get_keys(dn)
+            keys = self.get_keys(creds)
             self.creds_set_keys(creds, keys)
 
             if self.get_domain_functional_level() >= DS_DOMAIN_FUNCTION_2008:
@@ -2504,7 +2508,7 @@ class KDCBaseTest(RawKerberosTest):
 
         salt = creds.get_salt()
 
-        etype = self.get_default_enctypes()
+        etype = self.get_default_enctypes(creds)
         cname = self.PrincipalName_create(name_type=client_name_type,
                                           names=user_name.split('/'))
         if sname is None:
@@ -3039,7 +3043,9 @@ class KDCBaseTest(RawKerberosTest):
                                      lm_verifier=None)
 
         num, _ = err.exception.args
-        if protected:
+        if not self.expect_nt_hash:
+            self.assertEqual(ntstatus.NT_STATUS_NTLM_BLOCKED, num)
+        elif protected:
             self.assertEqual(ntstatus.NT_STATUS_ACCOUNT_RESTRICTION, num)
         else:
             self.assertEqual(ntstatus.NT_STATUS_WRONG_PASSWORD, num)
@@ -3055,7 +3061,9 @@ class KDCBaseTest(RawKerberosTest):
                                      password3=None)
 
         num, _ = err.exception.args
-        if protected:
+        if not self.expect_nt_hash:
+            self.assertEqual(ntstatus.NT_STATUS_NTLM_BLOCKED, num)
+        elif protected:
             self.assertEqual(ntstatus.NT_STATUS_ACCOUNT_RESTRICTION, num)
         else:
             self.assertEqual(ntstatus.NT_STATUS_WRONG_PASSWORD, num)
@@ -3142,13 +3150,17 @@ class KDCBaseTest(RawKerberosTest):
                                           validation_level,
                                           netr_flags))
         except NTSTATUSError as err:
-            self.assertTrue(protected, 'got unexpected error')
-
             num, _ = err.args
-            if num != ntstatus.NT_STATUS_ACCOUNT_RESTRICTION:
-                raise
+            if protected:
+                if num != ntstatus.NT_STATUS_ACCOUNT_RESTRICTION:
+                    raise
+            else:
+                self.assertFalse(self.expect_nt_hash, 'got unexpected error')
+                if num != ntstatus.NT_STATUS_NTLM_BLOCKED:
+                    raise
         else:
             self.assertFalse(protected, 'expected error')
+            self.assertTrue(self.expect_nt_hash, 'expected error')
 
             self.assertEqual(1, authoritative)
             self.assertEqual(0, flags)
index a8a85634c580becbf967543c71decb70ebf77fd4..46e516a53660295cef7dac3d1d0dbcfe3e4e2784 100755 (executable)
@@ -129,7 +129,7 @@ def connect_kdc(pipe,
     krbtgt_decryption_key = (
         as_req_base.TicketDecryptionKey_from_creds(krbtgt_creds))
 
-    etypes = as_req_base.get_default_enctypes()
+    etypes = as_req_base.get_default_enctypes(user_creds)
 
     if expect_error:
         expected_error_modes = (KDC_ERR_CLIENT_REVOKED,
index 8c325bf4747ba3cdcfc868dfa55b7bc742e89763..c9ed23b5fb9a1e96b851492641a7e85bcc2d24d1 100755 (executable)
@@ -190,10 +190,15 @@ class ProtectedUsersTests(KDCBaseTest):
 
         client_creds.set_password(new_password)
 
-        self.get_keys(client_dn,
-                      expected_etypes={kcrypto.Enctype.AES256,
-                                       kcrypto.Enctype.AES128,
-                                       kcrypto.Enctype.RC4})
+        expected_etypes = {
+            kcrypto.Enctype.AES256,
+            kcrypto.Enctype.AES128,
+        }
+        if self.expect_nt_hash:
+            expected_etypes.add(kcrypto.Enctype.RC4)
+
+        self.get_keys(client_creds,
+                      expected_etypes=expected_etypes)
 
     # Test that DES-CBC-CRC cannot be used whether or not the user is
     # protected.
index 18a93caf93d58896f0ed3f47f3ad73f087bd1cff..20e6a169dba2b5ba736d2712264114d6e4c6dc4d 100644 (file)
@@ -719,6 +719,12 @@ class RawKerberosTest(TestCaseInTempDir):
             forced_rc4 = '0'
         cls.forced_rc4 = bool(int(forced_rc4))
 
+        expect_nt_hash = samba.tests.env_get_var_value('EXPECT_NT_HASH',
+                                                       allow_missing=True)
+        if expect_nt_hash is None:
+            expect_nt_hash = '1'
+        cls.expect_nt_hash = bool(int(expect_nt_hash))
+
     def setUp(self):
         super().setUp()
         self.do_asn1_print = False
@@ -977,15 +983,22 @@ class RawKerberosTest(TestCaseInTempDir):
         return c
 
     # Overridden by KDCBaseTest. At this level we don't know what actual
-    # enctypes are supported, so assume they all are. This matches the
-    # behaviour that tests expect by default.
-    def get_default_enctypes(self):
-        return [
+    # enctypes are supported, so the best we can do is go by whether NT hashes
+    # are expected and whether the account is a workstation or not. This
+    # matches the behaviour that tests expect by default.
+    def get_default_enctypes(self, creds):
+        self.assertIsNotNone(creds)
+
+        default_enctypes = [
             kcrypto.Enctype.AES256,
             kcrypto.Enctype.AES128,
-            kcrypto.Enctype.RC4,
         ]
 
+        if self.expect_nt_hash or creds.get_workstation():
+            default_enctypes.append(kcrypto.Enctype.RC4)
+
+        return default_enctypes
+
     def asn1_dump(self, name, obj, asn1_print=None):
         if asn1_print is None:
             asn1_print = self.do_asn1_print
@@ -3955,7 +3968,8 @@ class RawKerberosTest(TestCaseInTempDir):
             return max(filter(lambda e: e in etypes, proposed_etypes),
                        default=None)
 
-        supported_etypes = self.get_default_enctypes()
+        creds = kdc_exchange_dict['creds']
+        supported_etypes = self.get_default_enctypes(creds)
 
         aes_etypes = set()
         if kcrypto.Enctype.AES256 in supported_etypes:
index 42e7b3428d6ca1ac53a6c384a522fe06f22eac4c..5bcc0bde3699c0732334a670cdf89be6110dfdb2 100755 (executable)
@@ -199,7 +199,7 @@ class SpnTests(KDCBaseTest):
         kvno = int(res[0].get('msDS-KeyVersionNumber', idx=0))
         creds.set_kvno(kvno)
 
-        keys = self.get_keys(rodc_dn)
+        keys = self.get_keys(creds)
         self.creds_set_keys(creds, keys)
 
         return creds