From 04e98669c3e403669505922805ac9feb37b578b8 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 14 Sep 2020 11:12:37 -0600 Subject: [PATCH 001/162] python: Move dsdb_Dn to samdb The import dsdb needed for dsdb_Dn causes import errors when trying to import get_bytes/get_string in some places. Signed-off-by: David Mulder Reviewed-by: Douglas Bagnall BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [abartlet@samba.org backported from commit 85d2ff2f0003b106ca84866b7e7893723f1dd93c as the PY2 compat code is still in place in Samba 4.13] --- python/samba/common.py | 79 ------------------------- python/samba/dbchecker.py | 2 +- python/samba/kcc/kcc_utils.py | 2 +- python/samba/kcc/ldif_import_export.py | 3 +- python/samba/samdb.py | 75 +++++++++++++++++++++++ python/samba/tests/common.py | 4 +- source4/torture/drs/python/repl_rodc.py | 2 +- 7 files changed, 81 insertions(+), 86 deletions(-) diff --git a/python/samba/common.py b/python/samba/common.py index 8876e4f4faa..a8faa90065d 100644 --- a/python/samba/common.py +++ b/python/samba/common.py @@ -16,13 +16,6 @@ # along with this program. If not, see . # - -import ldb -from samba import dsdb -from samba.ndr import ndr_pack -from samba.dcerpc import misc -import binascii - from samba.compat import PY3 @@ -74,75 +67,3 @@ def normalise_int32(ivalue): return str(ivalue) -class dsdb_Dn(object): - '''a class for binary DN''' - - def __init__(self, samdb, dnstring, syntax_oid=None): - '''create a dsdb_Dn''' - if syntax_oid is None: - # auto-detect based on string - if dnstring.startswith("B:"): - syntax_oid = dsdb.DSDB_SYNTAX_BINARY_DN - elif dnstring.startswith("S:"): - syntax_oid = dsdb.DSDB_SYNTAX_STRING_DN - else: - syntax_oid = dsdb.DSDB_SYNTAX_OR_NAME - if syntax_oid in [dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_STRING_DN]: - # it is a binary DN - colons = dnstring.split(':') - if len(colons) < 4: - raise RuntimeError("Invalid DN %s" % dnstring) - prefix_len = 4 + len(colons[1]) + int(colons[1]) - self.prefix = dnstring[0:prefix_len] - self.binary = self.prefix[3 + len(colons[1]):-1] - self.dnstring = dnstring[prefix_len:] - else: - self.dnstring = dnstring - self.prefix = '' - self.binary = '' - self.dn = ldb.Dn(samdb, self.dnstring) - - def __str__(self): - return self.prefix + str(self.dn.extended_str(mode=1)) - - def __cmp__(self, other): - ''' compare dsdb_Dn values similar to parsed_dn_compare()''' - dn1 = self - dn2 = other - guid1 = dn1.dn.get_extended_component("GUID") - guid2 = dn2.dn.get_extended_component("GUID") - - v = cmp(guid1, guid2) - if v != 0: - return v - v = cmp(dn1.binary, dn2.binary) - return v - - # In Python3, __cmp__ is replaced by these 6 methods - def __eq__(self, other): - return self.__cmp__(other) == 0 - - def __ne__(self, other): - return self.__cmp__(other) != 0 - - def __lt__(self, other): - return self.__cmp__(other) < 0 - - def __le__(self, other): - return self.__cmp__(other) <= 0 - - def __gt__(self, other): - return self.__cmp__(other) > 0 - - def __ge__(self, other): - return self.__cmp__(other) >= 0 - - def get_binary_integer(self): - '''return binary part of a dsdb_Dn as an integer, or None''' - if self.prefix == '': - return None - return int(self.binary, 16) - - def get_bytes(self): - '''return binary as a byte string''' - return binascii.unhexlify(self.binary) diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py index d12833d9390..0085b4a8515 100644 --- a/python/samba/dbchecker.py +++ b/python/samba/dbchecker.py @@ -28,7 +28,7 @@ from samba.dcerpc import misc from samba.dcerpc import drsuapi from samba.ndr import ndr_unpack, ndr_pack from samba.dcerpc import drsblobs -from samba.common import dsdb_Dn +from samba.samdb import dsdb_Dn from samba.dcerpc import security from samba.descriptor import get_wellknown_sds, get_diff_sds from samba.auth import system_session, admin_session diff --git a/python/samba/kcc/kcc_utils.py b/python/samba/kcc/kcc_utils.py index e0712e49c82..9b4a894b743 100644 --- a/python/samba/kcc/kcc_utils.py +++ b/python/samba/kcc/kcc_utils.py @@ -30,7 +30,7 @@ from samba.dcerpc import ( drsuapi, misc, ) -from samba.common import dsdb_Dn +from samba.samdb import dsdb_Dn from samba.ndr import ndr_unpack, ndr_pack from collections import Counter diff --git a/python/samba/kcc/ldif_import_export.py b/python/samba/kcc/ldif_import_export.py index 86453f1e5c9..7ec553edcb9 100644 --- a/python/samba/kcc/ldif_import_export.py +++ b/python/samba/kcc/ldif_import_export.py @@ -23,8 +23,7 @@ import os from samba import Ldb, ldb, read_and_sub_file from samba.auth import system_session -from samba.samdb import SamDB -from samba.common import dsdb_Dn +from samba.samdb import SamDB, dsdb_Dn class LdifError(Exception): diff --git a/python/samba/samdb.py b/python/samba/samdb.py index 36d668c4586..0c8880d5c75 100644 --- a/python/samba/samdb.py +++ b/python/samba/samdb.py @@ -35,7 +35,9 @@ from samba.common import normalise_int32 from samba.compat import text_type from samba.compat import binary_type from samba.compat import get_bytes +from samba.common import cmp from samba.dcerpc import security +import binascii __docformat__ = "restructuredText" @@ -1422,3 +1424,76 @@ schemaUpdateNow: 1 if not full_dn.is_child_of(domain_dn): full_dn.add_base(domain_dn) return full_dn + +class dsdb_Dn(object): + '''a class for binary DN''' + + def __init__(self, samdb, dnstring, syntax_oid=None): + '''create a dsdb_Dn''' + if syntax_oid is None: + # auto-detect based on string + if dnstring.startswith("B:"): + syntax_oid = dsdb.DSDB_SYNTAX_BINARY_DN + elif dnstring.startswith("S:"): + syntax_oid = dsdb.DSDB_SYNTAX_STRING_DN + else: + syntax_oid = dsdb.DSDB_SYNTAX_OR_NAME + if syntax_oid in [dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_STRING_DN]: + # it is a binary DN + colons = dnstring.split(':') + if len(colons) < 4: + raise RuntimeError("Invalid DN %s" % dnstring) + prefix_len = 4 + len(colons[1]) + int(colons[1]) + self.prefix = dnstring[0:prefix_len] + self.binary = self.prefix[3 + len(colons[1]):-1] + self.dnstring = dnstring[prefix_len:] + else: + self.dnstring = dnstring + self.prefix = '' + self.binary = '' + self.dn = ldb.Dn(samdb, self.dnstring) + + def __str__(self): + return self.prefix + str(self.dn.extended_str(mode=1)) + + def __cmp__(self, other): + ''' compare dsdb_Dn values similar to parsed_dn_compare()''' + dn1 = self + dn2 = other + guid1 = dn1.dn.get_extended_component("GUID") + guid2 = dn2.dn.get_extended_component("GUID") + + v = cmp(guid1, guid2) + if v != 0: + return v + v = cmp(dn1.binary, dn2.binary) + return v + + # In Python3, __cmp__ is replaced by these 6 methods + def __eq__(self, other): + return self.__cmp__(other) == 0 + + def __ne__(self, other): + return self.__cmp__(other) != 0 + + def __lt__(self, other): + return self.__cmp__(other) < 0 + + def __le__(self, other): + return self.__cmp__(other) <= 0 + + def __gt__(self, other): + return self.__cmp__(other) > 0 + + def __ge__(self, other): + return self.__cmp__(other) >= 0 + + def get_binary_integer(self): + '''return binary part of a dsdb_Dn as an integer, or None''' + if self.prefix == '': + return None + return int(self.binary, 16) + + def get_bytes(self): + '''return binary as a byte string''' + return binascii.unhexlify(self.binary) diff --git a/python/samba/tests/common.py b/python/samba/tests/common.py index d326f795f85..b7248b0826e 100644 --- a/python/samba/tests/common.py +++ b/python/samba/tests/common.py @@ -20,8 +20,8 @@ import samba import os import samba.tests -from samba.common import normalise_int32, dsdb_Dn -from samba.samdb import SamDB +from samba.common import normalise_int32 +from samba.samdb import SamDB, dsdb_Dn class CommonTests(samba.tests.TestCaseInTempDir): diff --git a/source4/torture/drs/python/repl_rodc.py b/source4/torture/drs/python/repl_rodc.py index 166ba5ba5db..21e70b8bc6f 100644 --- a/source4/torture/drs/python/repl_rodc.py +++ b/source4/torture/drs/python/repl_rodc.py @@ -37,7 +37,7 @@ from samba.join import DCJoinContext from samba.dcerpc import drsuapi, misc, drsblobs, security from samba.drs_utils import drs_DsBind, drs_Replicate from samba.ndr import ndr_unpack, ndr_pack -from samba.common import dsdb_Dn +from samba.samdb import dsdb_Dn from samba.credentials import Credentials import random -- 2.25.1 From 5e8db6412bd21808f1136899fcc79ca23b9f9434 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Thu, 11 Oct 2018 13:08:38 +1300 Subject: [PATCH 002/162] python/join: use the provided krbtgt link in cleanup_old_accounts Before we were putting it in an otherwise unused variable, and deleting the previous krbtgt_dn, if any. Signed-off-by: Douglas Bagnall Reviewed-by: Andreas Schneider Reviewed-by: David Mulder BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 98f6ece5ad03a822180796873197383c17c3c6d9) --- python/samba/join.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/join.py b/python/samba/join.py index 7273f3734d3..a35cf1d9a38 100644 --- a/python/samba/join.py +++ b/python/samba/join.py @@ -259,7 +259,7 @@ class DCJoinContext(object): ctx.del_noerror(res[0].dn, recursive=True) if "msDS-Krbtgtlink" in res[0]: - new_krbtgt_dn = res[0]["msDS-Krbtgtlink"][0] + ctx.new_krbtgt_dn = res[0]["msDS-Krbtgtlink"][0] ctx.del_noerror(ctx.new_krbtgt_dn) res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(), -- 2.25.1 From 34a8c411c41213870db5cfdb2d207277ac971ba6 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 17 Sep 2021 16:43:00 +1200 Subject: [PATCH 003/162] autobuild: allow AUTOBUILD_FAIL_IMMEDIATELY=0 (say from a gitlab variable) This allows making a push to do a full test ignoring errors without needing "HACK!!!" commits on top. Use like this: git push -o ci.variable='AUTOBUILD_FAIL_IMMEDIATELY=0' RN: Samba CI runs can now continue past the first error if AUTOBUILD_FAIL_IMMEDIATELY=0 is set BUG: https://bugzilla.samba.org/show_bug.cgi?id=14841 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andrew Bartlett Reviewed-by: Michael Adam [abartlet@samba.org backported from commit b81f6f3d71487085bb355392ce7f8eff2db5bb4d due to changes in 4.15 and later for the autobuild dependent jobs work that avoids rebuilding Samba in each task] Autobuild-User(v4-14-test): Jule Anger Autobuild-Date(v4-14-test): Thu Sep 23 08:54:03 UTC 2021 on sn-devel-184 (cherry picked from commit f53c532c2292d07ab3374920bd83c1266663038e) --- script/autobuild.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/script/autobuild.py b/script/autobuild.py index 0f837d0c109..9cfb4f520bc 100755 --- a/script/autobuild.py +++ b/script/autobuild.py @@ -154,7 +154,6 @@ def format_option(name, value=None): def make_test( cmd='make test', - FAIL_IMMEDIATELY=1, TESTS='', include_envs=None, exclude_envs=None): @@ -169,7 +168,13 @@ def make_test( TESTS = (TESTS + ' ' + ' '.join(test_options)).strip() _options = [] - if FAIL_IMMEDIATELY: + + # Allow getting a full CI with + # git push -o ci.variable='AUTOBUILD_FAIL_IMMEDIATELY=0' + + FAIL_IMMEDIATELY = os.getenv("AUTOBUILD_FAIL_IMMEDIATELY", "1") + + if int(FAIL_IMMEDIATELY): _options.append('FAIL_IMMEDIATELY=1') if TESTS: _options.append("TESTS='{}'".format(TESTS)) -- 2.25.1 From 28b33b5296db0da94bdbd2180af93116acbc7ddf Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 15:39:19 +1200 Subject: [PATCH 004/162] krb5pac.idl: Add ticket checksum PAC buffer type Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit ff2f38fae79220e16765e17671972f9a55eb7cce) --- librpc/idl/krb5pac.idl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl index fb360c1257f..3239d7656b6 100644 --- a/librpc/idl/krb5pac.idl +++ b/librpc/idl/krb5pac.idl @@ -112,7 +112,8 @@ interface krb5pac PAC_TYPE_KDC_CHECKSUM = 7, PAC_TYPE_LOGON_NAME = 10, PAC_TYPE_CONSTRAINED_DELEGATION = 11, - PAC_TYPE_UPN_DNS_INFO = 12 + PAC_TYPE_UPN_DNS_INFO = 12, + PAC_TYPE_TICKET_CHECKSUM = 16 } PAC_TYPE; typedef struct { @@ -128,6 +129,7 @@ interface krb5pac [case(PAC_TYPE_CONSTRAINED_DELEGATION)][subcontext(0xFFFFFC01)] PAC_CONSTRAINED_DELEGATION_CTR constrained_delegation; [case(PAC_TYPE_UPN_DNS_INFO)] PAC_UPN_DNS_INFO upn_dns_info; + [case(PAC_TYPE_TICKET_CHECKSUM)] PAC_SIGNATURE_DATA ticket_checksum; /* when new PAC info types are added they are supposed to be done in such a way that they are backwards compatible with existing servers. This makes it safe to just use a [default] for -- 2.25.1 From 73592c7bcbee7e00d184b6c425544ac6527a32f7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 15:40:59 +1200 Subject: [PATCH 005/162] security.idl: Add well-known SIDs for FAST Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 0092b4a3ed58b2c256d4dd9117cce927a3edde12) --- librpc/idl/security.idl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl index a92e8f1518e..9845becd826 100644 --- a/librpc/idl/security.idl +++ b/librpc/idl/security.idl @@ -292,6 +292,9 @@ interface security const string SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY = "S-1-18-1"; const string SID_SERVICE_ASSERTED_IDENTITY = "S-1-18-2"; + const string SID_COMPOUNDED_AUTHENTICATION = "S-1-5-21-0-0-0-496"; + const string SID_CLAIMS_VALID = "S-1-5-21-0-0-0-497"; + /* * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */ -- 2.25.1 From 46c00bf7f6813525413968380fa9b41f50fe888b Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 15:46:42 +1200 Subject: [PATCH 006/162] tests/krb5: Calculate expected salt if not given explicitly Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit c6badf818e9db44461979a931c74fc5ab6e80132) --- python/samba/tests/krb5/as_req_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/as_req_tests.py b/python/samba/tests/krb5/as_req_tests.py index 82ff3f4845c..09160bf6814 100755 --- a/python/samba/tests/krb5/as_req_tests.py +++ b/python/samba/tests/krb5/as_req_tests.py @@ -74,7 +74,7 @@ class AsReqKerberosTests(KDCBaseTest): expected_cname = cname expected_srealm = realm expected_sname = sname - expected_salt = client_creds.get_forced_salt() + expected_salt = client_creds.get_salt() if any(etype in client_as_etypes and etype in initial_etypes for etype in (kcrypto.Enctype.AES256, @@ -142,7 +142,7 @@ class AsReqKerberosTests(KDCBaseTest): expected_cname = cname expected_srealm = realm expected_sname = sname - expected_salt = client_creds.get_forced_salt() + expected_salt = client_creds.get_salt() till = self.get_KerberosTime(offset=36000) -- 2.25.1 From cc84aeea6d616ef52c9849b9e614f94214151169 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 15:50:26 +1200 Subject: [PATCH 007/162] tests/krb5: Add methods to obtain the length of checksum types Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 9924dd976183ea62b08f116f8b8bacc698bb9b95) --- python/samba/tests/krb5/kcrypto.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/python/samba/tests/krb5/kcrypto.py b/python/samba/tests/krb5/kcrypto.py index c861e3cc96e..2a72969de00 100755 --- a/python/samba/tests/krb5/kcrypto.py +++ b/python/samba/tests/krb5/kcrypto.py @@ -478,6 +478,7 @@ class _ChecksumProfile(object): # define: # * checksum # * verify (if verification is not just checksum-and-compare) + # * checksum_len @classmethod def verify(cls, key, keyusage, text, cksum): expected = cls.checksum(key, keyusage, text) @@ -504,6 +505,10 @@ class _SimplifiedChecksum(_ChecksumProfile): raise ValueError('Wrong key type for checksum') super(_SimplifiedChecksum, cls).verify(key, keyusage, text, cksum) + @classmethod + def checksum_len(cls): + return cls.macsize + class _SHA1AES128(_SimplifiedChecksum): macsize = 12 @@ -533,6 +538,10 @@ class _HMACMD5(_ChecksumProfile): raise ValueError('Wrong key type for checksum') super(_HMACMD5, cls).verify(key, keyusage, text, cksum) + @classmethod + def checksum_len(cls): + return hashes.MD5.digest_size + class _MD5(_ChecksumProfile): @classmethod @@ -540,6 +549,10 @@ class _MD5(_ChecksumProfile): # This is unkeyed! return SIMPLE_HASH(text, hashes.MD5) + @classmethod + def checksum_len(cls): + return hashes.MD5.digest_size + class _SHA1(_ChecksumProfile): @classmethod @@ -547,6 +560,10 @@ class _SHA1(_ChecksumProfile): # This is unkeyed! return SIMPLE_HASH(text, hashes.SHA1) + @classmethod + def checksum_len(cls): + return hashes.SHA1.digest_size + class _CRC32(_ChecksumProfile): @classmethod @@ -555,6 +572,10 @@ class _CRC32(_ChecksumProfile): cksum = (~crc32(text, 0xffffffff)) & 0xffffffff return pack(' Date: Wed, 1 Sep 2021 15:57:26 +1200 Subject: [PATCH 008/162] tests/krb5: Use signed integers to represent key version numbers in ASN.1 As specified in 'MS-KILE 3.1.5.8: Key Version Numbers', Windows uses signed 32-bit integers to represent key version numbers. This makes a difference for an RODC with a msDS-SecondaryKrbTgtNumber greater than 32767, where the kvno should be encoded in four bytes rather than five. Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 448b661bf8815a05f534926d8ee8d6f57d123c2c) --- python/samba/tests/krb5/raw_testcase.py | 2 +- python/samba/tests/krb5/rfc4120.asn1 | 2 +- python/samba/tests/krb5/rfc4120_pyasn1.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 6db17f2a118..c5ee5eb6083 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -995,7 +995,7 @@ class RawKerberosTest(TestCaseInTempDir): def EncryptedData_create(self, key, usage, plaintext): # EncryptedData ::= SEQUENCE { # etype [0] Int32 -- EncryptionType --, - # kvno [1] UInt32 OPTIONAL, + # kvno [1] Int32 OPTIONAL, # cipher [2] OCTET STRING -- ciphertext # } ciphertext = key.encrypt(usage, plaintext) diff --git a/python/samba/tests/krb5/rfc4120.asn1 b/python/samba/tests/krb5/rfc4120.asn1 index f47c1d00202..a37011ae932 100644 --- a/python/samba/tests/krb5/rfc4120.asn1 +++ b/python/samba/tests/krb5/rfc4120.asn1 @@ -124,7 +124,7 @@ KerberosFlags ::= BIT STRING (SIZE (1..32)) EncryptedData ::= SEQUENCE { etype [0] EncryptionType, --Int32 EncryptionType -- - kvno [1] UInt32 OPTIONAL, + kvno [1] Int32 OPTIONAL, cipher [2] OCTET STRING -- ciphertext } diff --git a/python/samba/tests/krb5/rfc4120_pyasn1.py b/python/samba/tests/krb5/rfc4120_pyasn1.py index 39ec8ed7982..a9e4bcbb18f 100644 --- a/python/samba/tests/krb5/rfc4120_pyasn1.py +++ b/python/samba/tests/krb5/rfc4120_pyasn1.py @@ -120,7 +120,7 @@ class EncryptedData(univ.Sequence): EncryptedData.componentType = namedtype.NamedTypes( namedtype.NamedType('etype', EncryptionType().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), - namedtype.OptionalNamedType('kvno', UInt32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))), + namedtype.OptionalNamedType('kvno', Int32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))), namedtype.NamedType('cipher', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))) ) -- 2.25.1 From 3935e1befe3e22abf21b715f5adbeb94a9bab5e3 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 16:05:39 +1200 Subject: [PATCH 009/162] tests/krb5: Add KDCOptions flag for constrained delegation Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 08086c43987abecc588ebd32ec846ff7e27a83b6) --- python/samba/tests/krb5/rfc4120.asn1 | 1 + python/samba/tests/krb5/rfc4120_pyasn1.py | 1 + 2 files changed, 2 insertions(+) diff --git a/python/samba/tests/krb5/rfc4120.asn1 b/python/samba/tests/krb5/rfc4120.asn1 index a37011ae932..e0831e1f86f 100644 --- a/python/samba/tests/krb5/rfc4120.asn1 +++ b/python/samba/tests/krb5/rfc4120.asn1 @@ -632,6 +632,7 @@ KDCOptionsValues ::= BIT STRING { -- KerberosFlags opt-hardware-auth(11), unused12(12), unused13(13), + cname-in-addl-tkt(14), -- Canonicalize is used by RFC 6806 canonicalize(15), -- 26 was unused in 1510 diff --git a/python/samba/tests/krb5/rfc4120_pyasn1.py b/python/samba/tests/krb5/rfc4120_pyasn1.py index a9e4bcbb18f..348dd8c63fb 100644 --- a/python/samba/tests/krb5/rfc4120_pyasn1.py +++ b/python/samba/tests/krb5/rfc4120_pyasn1.py @@ -649,6 +649,7 @@ KDCOptionsValues.namedValues = namedval.NamedValues( ('opt-hardware-auth', 11), ('unused12', 12), ('unused13', 13), + ('cname-in-addl-tkt', 14), ('canonicalize', 15), ('disable-transited-check', 26), ('renewable-ok', 27), -- 2.25.1 From e6387afe91c35f9ab864dc72c0c32d4bb2f355bf Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 16:21:55 +1200 Subject: [PATCH 010/162] tests/krb5: Use more compact dict lookup Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 3fd73b65a3db405db5a0a82cca6c808763d4f437) --- python/samba/tests/krb5/raw_testcase.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index c5ee5eb6083..0ec0f65c6d6 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -305,7 +305,7 @@ class KerberosCredentials(Credentials): def get_forced_key(self, etype): etype = int(etype) - return self.forced_keys.get(etype, None) + return self.forced_keys.get(etype) def set_forced_salt(self, salt): self.forced_salt = bytes(salt) @@ -830,7 +830,7 @@ class RawKerberosTest(TestCaseInTempDir): self.assertIsNotNone(value) def getElementValue(self, obj, elem): - return obj.get(elem, None) + return obj.get(elem) def assertElementMissing(self, obj, elem): v = self.getElementValue(obj, elem) @@ -942,7 +942,7 @@ class RawKerberosTest(TestCaseInTempDir): def PasswordKey_from_etype_info2(self, creds, etype_info2, kvno=None): e = etype_info2['etype'] - salt = etype_info2.get('salt', None) + salt = etype_info2.get('salt') if e == kcrypto.Enctype.RC4: nthash = creds.get_nt_hash() -- 2.25.1 From 344dd742659be6bccac281a53798dacf6b60a096 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 16:31:56 +1200 Subject: [PATCH 011/162] tests/krb5: Replace expected_cname_private with expected_anon parameter This is used in the case where the KDC returns 'WELLKNOWN/ANONYMOUS' as the cname, and makes the reply checking logic easier to follow. This also removes the need to fetch the client credentials in the test methods. Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit bf55786fcd9a96daa9002661d6f5d9b3502ed8a7) --- python/samba/tests/krb5/fast_tests.py | 33 +++++------------------- python/samba/tests/krb5/raw_testcase.py | 34 ++++++++++++------------- 2 files changed, 24 insertions(+), 43 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 2d4b69f8590..b371ab617aa 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -49,7 +49,6 @@ from samba.tests.krb5.rfc4120_constants import ( KU_TICKET, NT_PRINCIPAL, NT_SRV_INST, - NT_WELLKNOWN, PADATA_FX_COOKIE, PADATA_FX_FAST, PADATA_PAC_OPTIONS @@ -985,14 +984,6 @@ class FAST_Tests(KDCBaseTest): ]) def test_fast_hide_client_names(self): - user_creds = self.get_client_creds() - user_name = user_creds.get_username() - user_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, - names=[user_name]) - - expected_cname = self.PrincipalName_create( - name_type=NT_WELLKNOWN, names=['WELLKNOWN', 'ANONYMOUS']) - self._run_test_sequence([ { 'rep_type': KRB_AS_REP, @@ -1001,7 +992,7 @@ class FAST_Tests(KDCBaseTest): 'fast_armor': FX_FAST_ARMOR_AP_REQUEST, 'gen_armor_tgt_fn': self.get_mach_tgt, 'fast_options': '01', # hide client names - 'expected_cname': expected_cname + 'expected_anon': True }, { 'rep_type': KRB_AS_REP, @@ -1011,20 +1002,11 @@ class FAST_Tests(KDCBaseTest): 'fast_armor': FX_FAST_ARMOR_AP_REQUEST, 'gen_armor_tgt_fn': self.get_mach_tgt, 'fast_options': '01', # hide client names - 'expected_cname': expected_cname, - 'expected_cname_private': user_cname + 'expected_anon': True } ]) def test_fast_tgs_hide_client_names(self): - user_creds = self.get_client_creds() - user_name = user_creds.get_username() - user_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, - names=[user_name]) - - expected_cname = self.PrincipalName_create( - name_type=NT_WELLKNOWN, names=['WELLKNOWN', 'ANONYMOUS']) - self._run_test_sequence([ { 'rep_type': KRB_TGS_REP, @@ -1033,8 +1015,7 @@ class FAST_Tests(KDCBaseTest): 'gen_tgt_fn': self.get_user_tgt, 'fast_armor': None, 'fast_options': '01', # hide client names - 'expected_cname': expected_cname, - 'expected_cname_private': user_cname + 'expected_anon': True } ]) @@ -1216,8 +1197,8 @@ class FAST_Tests(KDCBaseTest): srealm = target_realm expected_cname = kdc_dict.pop('expected_cname', client_cname) - expected_cname_private = kdc_dict.pop('expected_cname_private', - None) + expected_anon = kdc_dict.pop('expected_anon', + False) expected_crealm = kdc_dict.pop('expected_crealm', client_realm) expected_sname = kdc_dict.pop('expected_sname', sname) expected_srealm = kdc_dict.pop('expected_srealm', srealm) @@ -1341,7 +1322,7 @@ class FAST_Tests(KDCBaseTest): kdc_exchange_dict = self.as_exchange_dict( expected_crealm=expected_crealm, expected_cname=expected_cname, - expected_cname_private=expected_cname_private, + expected_anon=expected_anon, expected_srealm=expected_srealm, expected_sname=expected_sname, ticket_decryption_key=krbtgt_decryption_key, @@ -1370,7 +1351,7 @@ class FAST_Tests(KDCBaseTest): kdc_exchange_dict = self.tgs_exchange_dict( expected_crealm=expected_crealm, expected_cname=expected_cname, - expected_cname_private=expected_cname_private, + expected_anon=expected_anon, expected_srealm=expected_srealm, expected_sname=expected_sname, ticket_decryption_key=target_decryption_key, diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 0ec0f65c6d6..e4dbb10d135 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1721,7 +1721,7 @@ class RawKerberosTest(TestCaseInTempDir): def as_exchange_dict(self, expected_crealm=None, expected_cname=None, - expected_cname_private=None, + expected_anon=False, expected_srealm=None, expected_sname=None, ticket_decryption_key=None, @@ -1759,6 +1759,7 @@ class RawKerberosTest(TestCaseInTempDir): 'rep_encpart_asn1Spec': krb5_asn1.EncASRepPart, 'expected_crealm': expected_crealm, 'expected_cname': expected_cname, + 'expected_anon': expected_anon, 'expected_srealm': expected_srealm, 'expected_sname': expected_sname, 'ticket_decryption_key': ticket_decryption_key, @@ -1784,10 +1785,6 @@ class RawKerberosTest(TestCaseInTempDir): 'inner_req': inner_req, 'outer_req': outer_req } - if expected_cname_private is not None: - kdc_exchange_dict['expected_cname_private'] = ( - expected_cname_private) - if callback_dict is None: callback_dict = {} @@ -1796,7 +1793,7 @@ class RawKerberosTest(TestCaseInTempDir): def tgs_exchange_dict(self, expected_crealm=None, expected_cname=None, - expected_cname_private=None, + expected_anon=False, expected_srealm=None, expected_sname=None, ticket_decryption_key=None, @@ -1834,6 +1831,7 @@ class RawKerberosTest(TestCaseInTempDir): 'rep_encpart_asn1Spec': krb5_asn1.EncTGSRepPart, 'expected_crealm': expected_crealm, 'expected_cname': expected_cname, + 'expected_anon': expected_anon, 'expected_srealm': expected_srealm, 'expected_sname': expected_sname, 'ticket_decryption_key': ticket_decryption_key, @@ -1859,10 +1857,6 @@ class RawKerberosTest(TestCaseInTempDir): 'inner_req': inner_req, 'outer_req': outer_req } - if expected_cname_private is not None: - kdc_exchange_dict['expected_cname_private'] = ( - expected_cname_private) - if callback_dict is None: callback_dict = {} @@ -1874,7 +1868,7 @@ class RawKerberosTest(TestCaseInTempDir): rep): expected_crealm = kdc_exchange_dict['expected_crealm'] - expected_cname = kdc_exchange_dict['expected_cname'] + expected_anon = kdc_exchange_dict['expected_anon'] expected_srealm = kdc_exchange_dict['expected_srealm'] expected_sname = kdc_exchange_dict['expected_sname'] ticket_decryption_key = kdc_exchange_dict['ticket_decryption_key'] @@ -1888,6 +1882,12 @@ class RawKerberosTest(TestCaseInTempDir): padata = self.getElementValue(rep, 'padata') if self.strict_checking: self.assertElementEqualUTF8(rep, 'crealm', expected_crealm) + if expected_anon: + expected_cname = self.PrincipalName_create( + name_type=NT_WELLKNOWN, + names=['WELLKNOWN', 'ANONYMOUS']) + else: + expected_cname = kdc_exchange_dict['expected_cname'] self.assertElementEqualPrincipal(rep, 'cname', expected_cname) self.assertElementPresent(rep, 'ticket') ticket = self.getElementValue(rep, 'ticket') @@ -2042,14 +2042,11 @@ class RawKerberosTest(TestCaseInTempDir): and kdc_options[canon_pos] == '1') expected_crealm = kdc_exchange_dict['expected_crealm'] + expected_cname = kdc_exchange_dict['expected_cname'] expected_srealm = kdc_exchange_dict['expected_srealm'] expected_sname = kdc_exchange_dict['expected_sname'] ticket_decryption_key = kdc_exchange_dict['ticket_decryption_key'] - try: - expected_cname = kdc_exchange_dict['expected_cname_private'] - except KeyError: - expected_cname = kdc_exchange_dict['expected_cname'] ticket = self.getElementValue(rep, 'ticket') @@ -2182,7 +2179,7 @@ class RawKerberosTest(TestCaseInTempDir): rep_msg_type = kdc_exchange_dict['rep_msg_type'] - expected_cname = kdc_exchange_dict['expected_cname'] + expected_anon = kdc_exchange_dict['expected_anon'] expected_srealm = kdc_exchange_dict['expected_srealm'] expected_sname = kdc_exchange_dict['expected_sname'] expected_error_mode = kdc_exchange_dict['expected_error_mode'] @@ -2203,7 +2200,10 @@ class RawKerberosTest(TestCaseInTempDir): # error-code checked above if self.strict_checking: self.assertElementMissing(rep, 'crealm') - if expected_cname['name-type'] == NT_WELLKNOWN and not inner: + if expected_anon and not inner: + expected_cname = self.PrincipalName_create( + name_type=NT_WELLKNOWN, + names=['WELLKNOWN', 'ANONYMOUS']) self.assertElementEqualPrincipal(rep, 'cname', expected_cname) else: self.assertElementMissing(rep, 'cname') -- 2.25.1 From 092a1939d7ccc498a078f942a619ea1e235392cc Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 16:34:02 +1200 Subject: [PATCH 012/162] tests/krb5: Allow specifying an OU to create accounts in Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 7aae0e9b100b8cb7d1da78b8cb9a4a5c20acffbd) --- python/samba/tests/krb5/kdc_base_test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index f5c1eba9151..efe11da8468 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -151,12 +151,16 @@ class KDCBaseTest(RawKerberosTest): return default_enctypes def create_account(self, ldb, name, machine_account=False, - spn=None, upn=None, additional_details=None): + spn=None, upn=None, additional_details=None, + ou=None): '''Create an account for testing. The dn of the created account is added to self.accounts, which is used by tearDownClass to clean up the created accounts. ''' - dn = "cn=%s,%s" % (name, ldb.domain_dn()) + if ou is None: + ou = ldb.domain_dn() + + dn = "CN=%s,%s" % (name, ou) # remove the account if it exists, this will happen if a previous test # run failed -- 2.25.1 From 90da0f10baa817f4e89015a4e899cd36617bbf41 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 16:34:46 +1200 Subject: [PATCH 013/162] tests/krb5: Allow specifying additional User Account Control flags for account Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 9aa900857441ea7e1c2d6c60bfa1ddeb142bf3e3) --- python/samba/tests/krb5/kdc_base_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index efe11da8468..bd5bacfaca1 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -152,7 +152,7 @@ class KDCBaseTest(RawKerberosTest): def create_account(self, ldb, name, machine_account=False, spn=None, upn=None, additional_details=None, - ou=None): + ou=None, account_control=0): '''Create an account for testing. The dn of the created account is added to self.accounts, which is used by tearDownClass to clean up the created accounts. @@ -168,11 +168,11 @@ class KDCBaseTest(RawKerberosTest): if machine_account: object_class = "computer" account_name = "%s$" % name - account_control = str(UF_WORKSTATION_TRUST_ACCOUNT) + account_control |= UF_WORKSTATION_TRUST_ACCOUNT else: object_class = "user" account_name = name - account_control = str(UF_NORMAL_ACCOUNT) + account_control |= UF_NORMAL_ACCOUNT password = generate_random_password(32, 32) utf16pw = ('"%s"' % password).encode('utf-16-le') @@ -181,7 +181,7 @@ class KDCBaseTest(RawKerberosTest): "dn": dn, "objectclass": object_class, "sAMAccountName": account_name, - "userAccountControl": account_control, + "userAccountControl": str(account_control), "unicodePwd": utf16pw} if spn is not None: details["servicePrincipalName"] = spn -- 2.25.1 From d8997d65476d8f9789e29d31adf7fcdf285af2ce Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 16:35:58 +1200 Subject: [PATCH 014/162] tests/krb5: Keep track of account DN in credentials object Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 9973b51e48a5d5f3e33c6e0da46e6231a42bd77a) --- python/samba/tests/krb5/kdc_base_test.py | 2 ++ python/samba/tests/krb5/raw_testcase.py | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index bd5bacfaca1..b52452358cc 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -201,6 +201,7 @@ class KDCBaseTest(RawKerberosTest): creds.set_workstation(name) else: creds.set_workstation('') + creds.set_dn(dn) # # Save the account name so it can be deleted in tearDownClass self.accounts.add(dn) @@ -441,6 +442,7 @@ class KDCBaseTest(RawKerberosTest): kvno = int(res[0]['msDS-KeyVersionNumber'][0]) creds.set_kvno(kvno) + creds.set_dn(dn) keys = self.get_keys(samdb, dn) self.creds_set_keys(creds, keys) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index e4dbb10d135..e62fad3d187 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -261,6 +261,8 @@ class KerberosCredentials(Credentials): self.forced_salt = None + self.dn = None + def set_as_supported_enctypes(self, value): self.as_supported_enctypes = int(value) @@ -327,6 +329,12 @@ class KerberosCredentials(Credentials): return salt_string.encode('utf-8') + def set_dn(self, dn): + self.dn = dn + + def get_dn(self): + return self.dn + class KerberosTicketCreds: def __init__(self, ticket, session_key, -- 2.25.1 From 2a564b93de1ec94d4988e718afdb87f4fed56461 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 2 Sep 2021 14:27:00 +1200 Subject: [PATCH 015/162] tests/krb5: Move padata generation methods to base class This allows them to be used directly from RawKerberosTest. Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 1f23b16ef3a900a1bda01bf2a5a3a3847e2e79d1) --- python/samba/tests/krb5/fast_tests.py | 14 -------------- python/samba/tests/krb5/raw_testcase.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index b371ab617aa..4fc297c1e34 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -51,7 +51,6 @@ from samba.tests.krb5.rfc4120_constants import ( NT_SRV_INST, PADATA_FX_COOKIE, PADATA_FX_FAST, - PADATA_PAC_OPTIONS ) import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1 import samba.tests.krb5.kcrypto as kcrypto @@ -1466,19 +1465,6 @@ class FAST_Tests(KDCBaseTest): return self.PA_DATA_create(PADATA_FX_COOKIE, cookie) - def get_pa_pac_request(self, request_pac=True): - pac_request = self.KERB_PA_PAC_REQUEST_create(request_pac) - - return pac_request - - def get_pa_pac_options(self, options): - pac_options = self.PA_PAC_OPTIONS_create(options) - pac_options = self.der_encode(pac_options, - asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) - pac_options = self.PA_DATA_create(PADATA_PAC_OPTIONS, pac_options) - - return pac_options - def check_kdc_fast_support(self): # Check that the KDC supports FAST diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index e62fad3d187..b724baf5cf8 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1151,6 +1151,19 @@ class RawKerberosTest(TestCaseInTempDir): pa_data = self.PA_DATA_create(PADATA_PAC_REQUEST, pa_pac) return pa_data + def get_pa_pac_request(self, request_pac=True): + pac_request = self.KERB_PA_PAC_REQUEST_create(request_pac) + + return pac_request + + def get_pa_pac_options(self, options): + pac_options = self.PA_PAC_OPTIONS_create(options) + pac_options = self.der_encode(pac_options, + asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) + pac_options = self.PA_DATA_create(PADATA_PAC_OPTIONS, pac_options) + + return pac_options + def KDC_REQ_BODY_create(self, kdc_options, cname, -- 2.25.1 From c54a7c5877cdba3d7025962e7b8fb49ebe0f5d67 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 2 Sep 2021 14:36:42 +1200 Subject: [PATCH 016/162] tests/krb5: add options to kdc_exchange_dict to specify including PAC-REQUEST or PAC-OPTIONS Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit c0db1ba54d238d4b2da8895215d8314b068ce09c) --- python/samba/tests/krb5/raw_testcase.py | 40 +++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index b724baf5cf8..58f246606d7 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1574,6 +1574,9 @@ class RawKerberosTest(TestCaseInTempDir): expected_error_mode = kdc_exchange_dict['expected_error_mode'] kdc_options = kdc_exchange_dict['kdc_options'] + pac_request = kdc_exchange_dict['pac_request'] + pac_options = kdc_exchange_dict['pac_options'] + # Parameters specific to the inner request body inner_req = kdc_exchange_dict['inner_req'] @@ -1619,6 +1622,14 @@ class RawKerberosTest(TestCaseInTempDir): else: del req_body[key] + additional_padata = [] + if pac_request is not None: + pa_pac_request = self.KERB_PA_PAC_REQUEST_create(pac_request) + additional_padata.append(pa_pac_request) + if pac_options is not None: + pa_pac_options = self.get_pa_pac_options(pac_options) + additional_padata.append(pa_pac_options) + if req_msg_type == KRB_AS_REQ: tgs_req = None tgs_req_padata = None @@ -1637,6 +1648,8 @@ class RawKerberosTest(TestCaseInTempDir): fast_padata, req_body = generate_fast_padata_fn(kdc_exchange_dict, callback_dict, req_body) + + fast_padata += additional_padata else: fast_padata = [] @@ -1701,6 +1714,9 @@ class RawKerberosTest(TestCaseInTempDir): if outer_padata is not None: padata += outer_padata + if fast is None: + padata += additional_padata + if not padata: padata = None @@ -1766,7 +1782,9 @@ class RawKerberosTest(TestCaseInTempDir): auth_data=None, kdc_options='', inner_req=None, - outer_req=None): + outer_req=None, + pac_request=None, + pac_options=None): if expected_error_mode == 0: expected_error_mode = () elif not isinstance(expected_error_mode, collections.abc.Container): @@ -1804,7 +1822,9 @@ class RawKerberosTest(TestCaseInTempDir): 'auth_data': auth_data, 'kdc_options': kdc_options, 'inner_req': inner_req, - 'outer_req': outer_req + 'outer_req': outer_req, + 'pac_request': pac_request, + 'pac_options': pac_options } if callback_dict is None: callback_dict = {} @@ -1838,7 +1858,9 @@ class RawKerberosTest(TestCaseInTempDir): body_checksum_type=None, kdc_options='', inner_req=None, - outer_req=None): + outer_req=None, + pac_request=None, + pac_options=None): if expected_error_mode == 0: expected_error_mode = () elif not isinstance(expected_error_mode, collections.abc.Container): @@ -1876,7 +1898,9 @@ class RawKerberosTest(TestCaseInTempDir): 'authenticator_subkey': authenticator_subkey, 'kdc_options': kdc_options, 'inner_req': inner_req, - 'outer_req': outer_req + 'outer_req': outer_req, + 'pac_request': pac_request, + 'pac_options': pac_options } if callback_dict is None: callback_dict = {} @@ -2820,7 +2844,9 @@ class RawKerberosTest(TestCaseInTempDir): padata, kdc_options, preauth_key=None, - ticket_decryption_key=None): + ticket_decryption_key=None, + pac_request=None, + pac_options=None): def _generate_padata_copy(_kdc_exchange_dict, _callback_dict, @@ -2860,7 +2886,9 @@ class RawKerberosTest(TestCaseInTempDir): expected_error_mode=expected_error_mode, client_as_etypes=client_as_etypes, expected_salt=expected_salt, - kdc_options=str(kdc_options)) + kdc_options=str(kdc_options), + pac_request=pac_request, + pac_options=pac_options) rep = self._generic_kdc_exchange(kdc_exchange_dict, cname=cname, -- 2.25.1 From 97d0e46aecb9eab71a68201082f2d10a592e02b9 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 2 Sep 2021 14:37:27 +1200 Subject: [PATCH 017/162] tests/krb5: Don't create PAC request manually in as_req_tests Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit bc21ba2592093c765751ed3e8083dcd3512997f8) --- python/samba/tests/krb5/as_req_tests.py | 35 ++++++++----------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/python/samba/tests/krb5/as_req_tests.py b/python/samba/tests/krb5/as_req_tests.py index 09160bf6814..35f88a0c920 100755 --- a/python/samba/tests/krb5/as_req_tests.py +++ b/python/samba/tests/krb5/as_req_tests.py @@ -56,7 +56,7 @@ class AsReqKerberosTests(KDCBaseTest): def _test_as_req_nopreauth(self, initial_etypes, - initial_padata=None, + pac=None, initial_kdc_options=None): client_creds = self.get_client_creds() client_account = client_creds.get_username() @@ -84,27 +84,19 @@ class AsReqKerberosTests(KDCBaseTest): else: expected_error_mode = KDC_ERR_ETYPE_NOSUPP - def _generate_padata_copy(_kdc_exchange_dict, - _callback_dict, - req_body): - return initial_padata, req_body - - generate_padata_fn = (_generate_padata_copy - if initial_padata is not None - else None) - kdc_exchange_dict = self.as_exchange_dict( expected_crealm=expected_crealm, expected_cname=expected_cname, expected_srealm=expected_srealm, expected_sname=expected_sname, - generate_padata_fn=generate_padata_fn, + generate_padata_fn=None, check_error_fn=self.generic_check_kdc_error, check_rep_fn=None, expected_error_mode=expected_error_mode, client_as_etypes=client_as_etypes, expected_salt=expected_salt, - kdc_options=str(initial_kdc_options)) + kdc_options=str(initial_kdc_options), + pac_request=pac) self._generic_kdc_exchange(kdc_exchange_dict, cname=cname, @@ -114,13 +106,8 @@ class AsReqKerberosTests(KDCBaseTest): def _test_as_req_no_preauth_with_args(self, etype_idx, pac): name, etypes = self.etype_test_permutation_by_idx(etype_idx) - if pac is None: - padata = None - else: - pa_pac = self.KERB_PA_PAC_REQUEST_create(pac) - padata = [pa_pac] self._test_as_req_nopreauth( - initial_padata=padata, + pac=pac, initial_etypes=etypes, initial_kdc_options=krb5_asn1.KDCOptions('forwardable')) @@ -146,8 +133,6 @@ class AsReqKerberosTests(KDCBaseTest): till = self.get_KerberosTime(offset=36000) - pa_pac = self.KERB_PA_PAC_REQUEST_create(True) - initial_padata = [pa_pac] initial_etypes = client_as_etypes initial_kdc_options = krb5_asn1.KDCOptions('forwardable') initial_error_mode = KDC_ERR_PREAUTH_REQUIRED @@ -164,8 +149,9 @@ class AsReqKerberosTests(KDCBaseTest): expected_sname, expected_salt, initial_etypes, - initial_padata, - initial_kdc_options) + None, + initial_kdc_options, + pac_request=True) etype_info2 = kdc_exchange_dict['preauth_etype_info2'] self.assertIsNotNone(etype_info2) @@ -183,7 +169,7 @@ class AsReqKerberosTests(KDCBaseTest): pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts) - preauth_padata = [pa_ts, pa_pac] + preauth_padata = [pa_ts] preauth_etypes = client_as_etypes preauth_kdc_options = krb5_asn1.KDCOptions('forwardable') preauth_error_mode = 0 # AS-REP @@ -207,7 +193,8 @@ class AsReqKerberosTests(KDCBaseTest): preauth_padata, preauth_kdc_options, preauth_key=preauth_key, - ticket_decryption_key=krbtgt_decryption_key) + ticket_decryption_key=krbtgt_decryption_key, + pac_request=True) self.assertIsNotNone(as_rep) if __name__ == "__main__": -- 2.25.1 From 1c57d81052e892de4c27814180cd0c2df2cee5d8 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 2 Sep 2021 14:38:33 +1200 Subject: [PATCH 018/162] tests/krb5: Don't create PAC request or options manually in fast_tests Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 7556a4dfa64650939aef14a2fc4d10b9ed3d29f7) --- python/samba/tests/krb5/fast_tests.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 4fc297c1e34..e10db90a57e 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1093,8 +1093,6 @@ class FAST_Tests(KDCBaseTest): 'canonicalize,' 'renewable-ok')) - pac_request = self.get_pa_pac_request() - client_creds = self.get_client_creds() target_creds = self.get_service_creds() krbtgt_creds = self.get_krbtgt_creds() @@ -1250,7 +1248,7 @@ class FAST_Tests(KDCBaseTest): _callback_dict, req_body, padata): - return padata, req_body + return list(padata), req_body def _check_padata_preauth_key(_kdc_exchange_dict, _callback_dict, @@ -1260,15 +1258,9 @@ class FAST_Tests(KDCBaseTest): return preauth_key, as_rep_usage pac_options = kdc_dict.pop('pac_options', '1') # claims support - pac_options = self.get_pa_pac_options(pac_options) kdc_options = kdc_dict.pop('kdc_options', kdc_options_default) - if rep_type == KRB_AS_REP: - padata = [pac_request, pac_options] - else: - padata = [pac_options] - gen_padata_fn = kdc_dict.pop('gen_padata_fn', None) if gen_padata_fn is not None: self.assertEqual(KRB_AS_REP, rep_type) @@ -1278,10 +1270,10 @@ class FAST_Tests(KDCBaseTest): client_creds, preauth_etype_info2[0], client_creds.get_kvno()) - gen_padata = gen_padata_fn(preauth_key, armor_key) - padata.insert(0, gen_padata) + padata = [gen_padata_fn(preauth_key, armor_key)] else: preauth_key = None + padata = [] if rep_type == KRB_AS_REP: check_padata_fn = _check_padata_preauth_key @@ -1345,7 +1337,9 @@ class FAST_Tests(KDCBaseTest): armor_subkey=armor_subkey, kdc_options=kdc_options, inner_req=inner_req, - outer_req=outer_req) + outer_req=outer_req, + pac_request=True, + pac_options=pac_options) else: # KRB_TGS_REP kdc_exchange_dict = self.tgs_exchange_dict( expected_crealm=expected_crealm, @@ -1374,7 +1368,9 @@ class FAST_Tests(KDCBaseTest): body_checksum_type=None, kdc_options=kdc_options, inner_req=inner_req, - outer_req=outer_req) + outer_req=outer_req, + pac_request=None, + pac_options=pac_options) repeat = kdc_dict.pop('repeat', 1) for _ in range(repeat): -- 2.25.1 From 93457cced299ddaadfe44bd0c5f64e6d45e3f4b3 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 17:46:02 +1200 Subject: [PATCH 019/162] tests/krb5: Remove magic constants Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 571265257f335ba7f6f1b46daa0d657b8a8dff2b) --- python/samba/tests/krb5/fast_tests.py | 2 +- python/samba/tests/krb5/kdc_base_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index e10db90a57e..29a666aad5e 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1466,7 +1466,7 @@ class FAST_Tests(KDCBaseTest): samdb = self.get_samdb() - krbtgt_rid = 502 + krbtgt_rid = security.DOMAIN_RID_KRBTGT krbtgt_sid = '%s-%d' % (samdb.get_domain_sid(), krbtgt_rid) res = samdb.search(base='' % krbtgt_sid, diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index b52452358cc..ac43b2eae1a 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -425,7 +425,7 @@ class KDCBaseTest(RawKerberosTest): def download_krbtgt_creds(): samdb = self.get_samdb() - krbtgt_rid = 502 + krbtgt_rid = security.DOMAIN_RID_KRBTGT krbtgt_sid = '%s-%d' % (samdb.get_domain_sid(), krbtgt_rid) res = samdb.search(base='' % krbtgt_sid, -- 2.25.1 From 444ed2e7b19e7280f59f39aec220bccdaaec0664 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 19:13:11 +1200 Subject: [PATCH 020/162] tests/krb5: Allow specifying ticket flags expected to be set or reset Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 85ddfc1afcf21797dab15431a5f375444c4d316e) --- python/samba/tests/krb5/fast_tests.py | 11 +++++++ python/samba/tests/krb5/raw_testcase.py | 40 +++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 29a666aad5e..687f7532a64 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1309,6 +1309,13 @@ class FAST_Tests(KDCBaseTest): inner_req = kdc_dict.pop('inner_req', None) outer_req = kdc_dict.pop('outer_req', None) + expected_flags = kdc_dict.pop('expected_flags', None) + if expected_flags is not None: + expected_flags = krb5_asn1.KDCOptions(expected_flags) + unexpected_flags = kdc_dict.pop('unexpected_flags', None) + if unexpected_flags is not None: + unexpected_flags = krb5_asn1.KDCOptions(unexpected_flags) + if rep_type == KRB_AS_REP: kdc_exchange_dict = self.as_exchange_dict( expected_crealm=expected_crealm, @@ -1316,6 +1323,8 @@ class FAST_Tests(KDCBaseTest): expected_anon=expected_anon, expected_srealm=expected_srealm, expected_sname=expected_sname, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, ticket_decryption_key=krbtgt_decryption_key, generate_fast_fn=generate_fast_fn, generate_fast_armor_fn=generate_fast_armor_fn, @@ -1347,6 +1356,8 @@ class FAST_Tests(KDCBaseTest): expected_anon=expected_anon, expected_srealm=expected_srealm, expected_sname=expected_sname, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, ticket_decryption_key=target_decryption_key, generate_fast_fn=generate_fast_fn, generate_fast_armor_fn=generate_fast_armor_fn, diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 58f246606d7..268f6ccc6bb 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -896,6 +896,24 @@ class RawKerberosTest(TestCaseInTempDir): else: self.assertIsNone(v) + def assertElementFlags(self, obj, elem, expected, unexpected): + v = self.getElementValue(obj, elem) + self.assertIsNotNone(v) + if expected is not None: + self.assertIsInstance(expected, krb5_asn1.KDCOptions) + for i, flag in enumerate(expected): + if flag == 1: + self.assertEqual('1', v[i], + f"'{expected.namedValues[i]}' " + f"expected in {v}") + if unexpected is not None: + self.assertIsInstance(unexpected, krb5_asn1.KDCOptions) + for i, flag in enumerate(unexpected): + if flag == 1: + self.assertEqual('0', v[i], + f"'{unexpected.namedValues[i]}' " + f"unexpected in {v}") + def get_KerberosTimeWithUsec(self, epoch=None, offset=None): if epoch is None: epoch = time.time() @@ -1761,6 +1779,8 @@ class RawKerberosTest(TestCaseInTempDir): expected_anon=False, expected_srealm=None, expected_sname=None, + expected_flags=None, + unexpected_flags=None, ticket_decryption_key=None, generate_fast_fn=None, generate_fast_armor_fn=None, @@ -1801,6 +1821,8 @@ class RawKerberosTest(TestCaseInTempDir): 'expected_anon': expected_anon, 'expected_srealm': expected_srealm, 'expected_sname': expected_sname, + 'expected_flags': expected_flags, + 'unexpected_flags': unexpected_flags, 'ticket_decryption_key': ticket_decryption_key, 'generate_fast_fn': generate_fast_fn, 'generate_fast_armor_fn': generate_fast_armor_fn, @@ -1837,6 +1859,8 @@ class RawKerberosTest(TestCaseInTempDir): expected_anon=False, expected_srealm=None, expected_sname=None, + expected_flags=None, + unexpected_flags=None, ticket_decryption_key=None, generate_fast_fn=None, generate_fast_armor_fn=None, @@ -1877,6 +1901,8 @@ class RawKerberosTest(TestCaseInTempDir): 'expected_anon': expected_anon, 'expected_srealm': expected_srealm, 'expected_sname': expected_sname, + 'expected_flags': expected_flags, + 'unexpected_flags': unexpected_flags, 'ticket_decryption_key': ticket_decryption_key, 'generate_fast_fn': generate_fast_fn, 'generate_fast_armor_fn': generate_fast_armor_fn, @@ -2092,6 +2118,8 @@ class RawKerberosTest(TestCaseInTempDir): expected_sname = kdc_exchange_dict['expected_sname'] ticket_decryption_key = kdc_exchange_dict['ticket_decryption_key'] + expected_flags = kdc_exchange_dict.get('expected_flags') + unexpected_flags = kdc_exchange_dict.get('unexpected_flags') ticket = self.getElementValue(rep, 'ticket') @@ -2101,7 +2129,9 @@ class RawKerberosTest(TestCaseInTempDir): ticket_session_key = None if ticket_private is not None: - self.assertElementPresent(ticket_private, 'flags') + self.assertElementFlags(ticket_private, 'flags', + expected_flags, + unexpected_flags) self.assertElementPresent(ticket_private, 'key') ticket_key = self.getElementValue(ticket_private, 'key') self.assertIsNotNone(ticket_key) @@ -2137,7 +2167,9 @@ class RawKerberosTest(TestCaseInTempDir): kdc_exchange_dict['nonce']) # TODO self.assertElementPresent(encpart_private, # 'key-expiration') - self.assertElementPresent(encpart_private, 'flags') + self.assertElementFlags(ticket_private, 'flags', + expected_flags, + unexpected_flags) self.assertElementPresent(encpart_private, 'authtime') if self.strict_checking: self.assertElementPresent(encpart_private, 'starttime') @@ -2843,6 +2875,8 @@ class RawKerberosTest(TestCaseInTempDir): etypes, padata, kdc_options, + expected_flags=None, + unexpected_flags=None, preauth_key=None, ticket_decryption_key=None, pac_request=None, @@ -2886,6 +2920,8 @@ class RawKerberosTest(TestCaseInTempDir): expected_error_mode=expected_error_mode, client_as_etypes=client_as_etypes, expected_salt=expected_salt, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, kdc_options=str(kdc_options), pac_request=pac_request, pac_options=pac_options) -- 2.25.1 From e151496f35eb717da78fa0c079a23259d6c0938f Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 19:15:17 +1200 Subject: [PATCH 021/162] tests/krb5: Make time assertion less strict This assertion could fail if there was a time difference between the KDC and the client. Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 1974b872fb5a7da052305d01e2f1efc8d0637078) --- python/samba/tests/krb5/raw_testcase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 268f6ccc6bb..5ae8fe4ba41 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2559,7 +2559,7 @@ class RawKerberosTest(TestCaseInTempDir): current_time = time.time() self.assertLess(current_time - 300, rep_time) - self.assertLess(rep_time, current_time) + self.assertLess(rep_time, current_time + 300) if all(etype not in client_as_etypes or etype not in proposed_etypes for etype in (kcrypto.Enctype.AES256, -- 2.25.1 From 182015f34f16f018d5357479fa5d02752f70c832 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 19:34:20 +1200 Subject: [PATCH 022/162] tests/krb5: Allow Kerberos requests to be sent to DC or RODC If run inside the 'rodc' testing environment, 'DC_SERVER' and 'SERVER' refer to the hostnames of the DC and RODC respectively, and this commit allows either one of them to be used as the KDC for Kerberos exchanges. Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 0afb548a0a3221730c4a81d51bc31e99ec90e334) --- python/samba/tests/krb5/kdc_base_test.py | 2 +- python/samba/tests/krb5/raw_testcase.py | 39 +++++++++++++++--------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index ac43b2eae1a..0755040a87a 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -116,7 +116,7 @@ class KDCBaseTest(RawKerberosTest): lp = self.get_lp() session = system_session() - type(self)._ldb = SamDB(url="ldap://%s" % self.host, + type(self)._ldb = SamDB(url="ldap://%s" % self.dc_host, session_info=session, credentials=creds, lp=lp) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 5ae8fe4ba41..c03600f765b 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -418,6 +418,7 @@ class RawKerberosTest(TestCaseInTempDir): super().setUpClass() cls.host = samba.tests.env_get_var_value('SERVER') + cls.dc_host = samba.tests.env_get_var_value('DC_SERVER') # A dictionary containing credentials that have already been # obtained. @@ -452,10 +453,10 @@ class RawKerberosTest(TestCaseInTempDir): if self.do_hexdump: sys.stderr.write("disconnect[%s]\n" % reason) - def _connect_tcp(self): + def _connect_tcp(self, host): tcp_port = 88 try: - self.a = socket.getaddrinfo(self.host, tcp_port, socket.AF_UNSPEC, + self.a = socket.getaddrinfo(host, tcp_port, socket.AF_UNSPEC, socket.SOCK_STREAM, socket.SOL_TCP, 0) self.s = socket.socket(self.a[0][0], self.a[0][1], self.a[0][2]) @@ -468,11 +469,11 @@ class RawKerberosTest(TestCaseInTempDir): self.s.close() raise - def connect(self): + def connect(self, host): self.assertNotConnected() - self._connect_tcp() + self._connect_tcp(host) if self.do_hexdump: - sys.stderr.write("connected[%s]\n" % self.host) + sys.stderr.write("connected[%s]\n" % host) def env_get_var(self, varname, prefix, fallback_default=True, @@ -819,8 +820,10 @@ class RawKerberosTest(TestCaseInTempDir): req, asn1_print=None, hexdump=None, - timeout=None): - self.connect() + timeout=None, + to_rodc=False): + host = self.host if to_rodc else self.dc_host + self.connect(host) try: self.send_pdu(req, asn1_print=asn1_print, hexdump=hexdump) rep = self.recv_pdu( @@ -1747,7 +1750,9 @@ class RawKerberosTest(TestCaseInTempDir): req_body=req_body, asn1Spec=req_asn1Spec()) - rep = self.send_recv_transaction(req_decoded) + to_rodc = kdc_exchange_dict['to_rodc'] + + rep = self.send_recv_transaction(req_decoded, to_rodc=to_rodc) self.assertIsNotNone(rep) msg_type = self.getElementValue(rep, 'msg-type') @@ -1804,7 +1809,8 @@ class RawKerberosTest(TestCaseInTempDir): inner_req=None, outer_req=None, pac_request=None, - pac_options=None): + pac_options=None, + to_rodc=False): if expected_error_mode == 0: expected_error_mode = () elif not isinstance(expected_error_mode, collections.abc.Container): @@ -1846,7 +1852,8 @@ class RawKerberosTest(TestCaseInTempDir): 'inner_req': inner_req, 'outer_req': outer_req, 'pac_request': pac_request, - 'pac_options': pac_options + 'pac_options': pac_options, + 'to_rodc': to_rodc } if callback_dict is None: callback_dict = {} @@ -1884,7 +1891,8 @@ class RawKerberosTest(TestCaseInTempDir): inner_req=None, outer_req=None, pac_request=None, - pac_options=None): + pac_options=None, + to_rodc=False): if expected_error_mode == 0: expected_error_mode = () elif not isinstance(expected_error_mode, collections.abc.Container): @@ -1926,7 +1934,8 @@ class RawKerberosTest(TestCaseInTempDir): 'inner_req': inner_req, 'outer_req': outer_req, 'pac_request': pac_request, - 'pac_options': pac_options + 'pac_options': pac_options, + 'to_rodc': to_rodc } if callback_dict is None: callback_dict = {} @@ -2880,7 +2889,8 @@ class RawKerberosTest(TestCaseInTempDir): preauth_key=None, ticket_decryption_key=None, pac_request=None, - pac_options=None): + pac_options=None, + to_rodc=False): def _generate_padata_copy(_kdc_exchange_dict, _callback_dict, @@ -2924,7 +2934,8 @@ class RawKerberosTest(TestCaseInTempDir): unexpected_flags=unexpected_flags, kdc_options=str(kdc_options), pac_request=pac_request, - pac_options=pac_options) + pac_options=pac_options, + to_rodc=to_rodc) rep = self._generic_kdc_exchange(kdc_exchange_dict, cname=cname, -- 2.25.1 From 4b1a967f53550d9ebad219e582567dd01cdbfe2b Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 19:43:41 +1200 Subject: [PATCH 023/162] tests/krb5: Check for presence of 'renew-till' element Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 9cba5f9a1b098e49315e2e3d4c0b626884c04a64) --- python/samba/tests/krb5/raw_testcase.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index c03600f765b..45ce3c092ad 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2120,6 +2120,9 @@ class RawKerberosTest(TestCaseInTempDir): canon_pos = len(tuple(krb5_asn1.KDCOptions('canonicalize'))) - 1 canonicalize = (canon_pos < len(kdc_options) and kdc_options[canon_pos] == '1') + renewable_pos = len(tuple(krb5_asn1.KDCOptions('renewable'))) - 1 + renewable = (renewable_pos < len(kdc_options) + and kdc_options[renewable_pos] == '1') expected_crealm = kdc_exchange_dict['expected_crealm'] expected_cname = kdc_exchange_dict['expected_cname'] @@ -2158,7 +2161,11 @@ class RawKerberosTest(TestCaseInTempDir): if self.strict_checking: self.assertElementPresent(ticket_private, 'starttime') self.assertElementPresent(ticket_private, 'endtime') - # TODO self.assertElementPresent(ticket_private, 'renew-till') + if renewable: + if self.strict_checking: + self.assertElementPresent(ticket_private, 'renew-till') + else: + self.assertElementMissing(ticket_private, 'renew-till') # TODO self.assertElementMissing(ticket_private, 'caddr') self.assertElementPresent(ticket_private, 'authorization-data') @@ -2183,7 +2190,11 @@ class RawKerberosTest(TestCaseInTempDir): if self.strict_checking: self.assertElementPresent(encpart_private, 'starttime') self.assertElementPresent(encpart_private, 'endtime') - # TODO self.assertElementPresent(encpart_private, 'renew-till') + if renewable: + if self.strict_checking: + self.assertElementPresent(encpart_private, 'renew-till') + else: + self.assertElementMissing(encpart_private, 'renew-till') self.assertElementEqualUTF8(encpart_private, 'srealm', expected_srealm) self.assertElementEqualPrincipal(encpart_private, 'sname', -- 2.25.1 From 630d758134787c37097e9a10a1e6de219637b267 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 19:45:57 +1200 Subject: [PATCH 024/162] tests/krb5: Check 'caddr' element Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit d3106a8d35225e826d548d3bea0d42edc3998c38) --- python/samba/tests/krb5/raw_testcase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 45ce3c092ad..9e47897dd76 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2166,7 +2166,8 @@ class RawKerberosTest(TestCaseInTempDir): self.assertElementPresent(ticket_private, 'renew-till') else: self.assertElementMissing(ticket_private, 'renew-till') - # TODO self.assertElementMissing(ticket_private, 'caddr') + if self.strict_checking: + self.assertElementEqual(ticket_private, 'caddr', []) self.assertElementPresent(ticket_private, 'authorization-data') encpart_session_key = None @@ -2199,7 +2200,8 @@ class RawKerberosTest(TestCaseInTempDir): expected_srealm) self.assertElementEqualPrincipal(encpart_private, 'sname', expected_sname) - # TODO self.assertElementMissing(encpart_private, 'caddr') + if self.strict_checking: + self.assertElementEqual(encpart_private, 'caddr', []) sent_claims = self.sent_claims(kdc_exchange_dict) -- 2.25.1 From 97ecd7fb8cc74c2040b0dfd0692e30ee1063744d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 19:47:27 +1200 Subject: [PATCH 025/162] tests/krb5: Check for presence of 'key-expiration' element Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit c3b746290278f7b5c1dea676e3fa28b9f15bcf94) --- python/samba/tests/krb5/raw_testcase.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 9e47897dd76..e754794e48b 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2130,6 +2130,8 @@ class RawKerberosTest(TestCaseInTempDir): expected_sname = kdc_exchange_dict['expected_sname'] ticket_decryption_key = kdc_exchange_dict['ticket_decryption_key'] + rep_msg_type = kdc_exchange_dict['rep_msg_type'] + expected_flags = kdc_exchange_dict.get('expected_flags') unexpected_flags = kdc_exchange_dict.get('unexpected_flags') @@ -2182,8 +2184,13 @@ class RawKerberosTest(TestCaseInTempDir): self.assertElementPresent(encpart_private, 'last-req') self.assertElementEqual(encpart_private, 'nonce', kdc_exchange_dict['nonce']) - # TODO self.assertElementPresent(encpart_private, - # 'key-expiration') + if rep_msg_type == KRB_AS_REP: + if self.strict_checking: + self.assertElementPresent(encpart_private, + 'key-expiration') + else: + self.assertElementMissing(encpart_private, + 'key-expiration') self.assertElementFlags(ticket_private, 'flags', expected_flags, unexpected_flags) -- 2.25.1 From 2124821d5c3c770034aaa3522eee50ef38617849 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 3 Sep 2021 09:18:32 +1200 Subject: [PATCH 026/162] tests/krb5: Create testing accounts in appropriate containers Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Isaac Boukris BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Sep 14 00:01:44 UTC 2021 on sn-devel-184 (cherry picked from commit 01378a52a1cf0b6855492673455013d5719be45b) --- python/samba/tests/krb5/kdc_base_test.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 0755040a87a..49a3227c26e 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -34,6 +34,8 @@ from samba.drs_utils import drsuapi_connect from samba.dsdb import ( DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2008, + DS_GUID_COMPUTERS_CONTAINER, + DS_GUID_USERS_CONTAINER, UF_WORKSTATION_TRUST_ACCOUNT, UF_NORMAL_ACCOUNT ) @@ -158,7 +160,10 @@ class KDCBaseTest(RawKerberosTest): which is used by tearDownClass to clean up the created accounts. ''' if ou is None: - ou = ldb.domain_dn() + guid = (DS_GUID_COMPUTERS_CONTAINER if machine_account + else DS_GUID_USERS_CONTAINER) + + ou = ldb.get_wellknown_dn(ldb.get_default_basedn(), guid) dn = "CN=%s,%s" % (name, ou) -- 2.25.1 From 92afc8bdbe96ea9887515c1aa0bc8a4951292bec Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 19:26:43 +1200 Subject: [PATCH 027/162] tests/krb5: Allow specifying status code to be checked This allows us to check the status code that may be sent in an error reply to a TGS-REQ message. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit 4ba5e82ae53410ec9a0bc7d47b181a88c15d9387) --- python/samba/tests/krb5/raw_testcase.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index e754794e48b..f65811243ba 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1798,6 +1798,7 @@ class RawKerberosTest(TestCaseInTempDir): check_kdc_private_fn=None, callback_dict=None, expected_error_mode=0, + expected_status=None, client_as_etypes=None, expected_salt=None, authenticator_subkey=None, @@ -1841,6 +1842,7 @@ class RawKerberosTest(TestCaseInTempDir): 'check_kdc_private_fn': check_kdc_private_fn, 'callback_dict': callback_dict, 'expected_error_mode': expected_error_mode, + 'expected_status': expected_status, 'client_as_etypes': client_as_etypes, 'expected_salt': expected_salt, 'authenticator_subkey': authenticator_subkey, @@ -1879,6 +1881,7 @@ class RawKerberosTest(TestCaseInTempDir): check_padata_fn=None, check_kdc_private_fn=None, expected_error_mode=0, + expected_status=None, callback_dict=None, tgt=None, armor_key=None, @@ -1923,6 +1926,7 @@ class RawKerberosTest(TestCaseInTempDir): 'check_kdc_private_fn': check_kdc_private_fn, 'callback_dict': callback_dict, 'expected_error_mode': expected_error_mode, + 'expected_status': expected_status, 'tgt': tgt, 'body_checksum_type': body_checksum_type, 'armor_key': armor_key, @@ -2540,7 +2544,12 @@ class RawKerberosTest(TestCaseInTempDir): status = int.from_bytes(pw_salt[:4], 'little') flags = int.from_bytes(pw_salt[8:], 'little') + expected_status = kdc_exchange_dict['expected_status'] + self.assertEqual(expected_status, status) + self.assertEqual(3, flags) + else: + self.assertIsNone(kdc_exchange_dict.get('expected_status')) if enc_challenge is not None: if not sent_enc_challenge: -- 2.25.1 From f02fe473129462610159e5f18943f5fe61eeaf42 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 3 Sep 2021 09:40:02 +1200 Subject: [PATCH 028/162] tests/krb5: Get expected cname from TGT for TGS-REQ messages BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit a5186f92803009c81eca2957e1bf2eb0ff7b6dff) --- python/samba/tests/krb5/fast_tests.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 687f7532a64..e1ba4628994 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -179,18 +179,12 @@ class FAST_Tests(KDCBaseTest): ]) def test_simple_tgs_wrong_principal(self): - mach_creds = self.get_mach_creds() - mach_name = mach_creds.get_username() - expected_cname = self.PrincipalName_create( - name_type=NT_PRINCIPAL, names=[mach_name]) - self._run_test_sequence([ { 'rep_type': KRB_TGS_REP, 'expected_error_mode': 0, 'use_fast': False, - 'gen_tgt_fn': self.get_mach_tgt, - 'expected_cname': expected_cname + 'gen_tgt_fn': self.get_mach_tgt } ]) @@ -1193,7 +1187,12 @@ class FAST_Tests(KDCBaseTest): else: # KRB_TGS_REP srealm = target_realm - expected_cname = kdc_dict.pop('expected_cname', client_cname) + if rep_type == KRB_TGS_REP: + tgt_cname = tgt.cname + else: + tgt_cname = client_cname + + expected_cname = kdc_dict.pop('expected_cname', tgt_cname) expected_anon = kdc_dict.pop('expected_anon', False) expected_crealm = kdc_dict.pop('expected_crealm', client_realm) -- 2.25.1 From cd8a71d62d73e438a794d9154a1c79cecd696730 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 3 Sep 2021 09:55:10 +1200 Subject: [PATCH 029/162] tests/krb5: Get encpart decryption key from kdc_exchange_dict Instead of using check_padata_fn to get the encpart decryption key, we can get the key from the AS-REQ preauth phase or from the TGT, depending on whether the message is an AS-REQ or a TGS-REQ. This allows removal of check_padata_fn and some duplicated code. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit 0e99382d73f44eed7e19e83e430938d587e762d0) --- python/samba/tests/krb5/fast_tests.py | 18 +--- python/samba/tests/krb5/raw_testcase.py | 122 ++++++++++-------------- 2 files changed, 54 insertions(+), 86 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index e1ba4628994..12235cd439e 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -45,7 +45,6 @@ from samba.tests.krb5.rfc4120_constants import ( KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS, KRB_AS_REP, KRB_TGS_REP, - KU_AS_REP_ENC_PART, KU_TICKET, NT_PRINCIPAL, NT_SRV_INST, @@ -1114,8 +1113,6 @@ class FAST_Tests(KDCBaseTest): fast_cookie = None preauth_etype_info2 = None - preauth_key = None - for kdc_dict in test_sequence: rep_type = kdc_dict.pop('rep_type') self.assertIn(rep_type, (KRB_AS_REP, KRB_TGS_REP)) @@ -1249,13 +1246,6 @@ class FAST_Tests(KDCBaseTest): padata): return list(padata), req_body - def _check_padata_preauth_key(_kdc_exchange_dict, - _callback_dict, - _rep, - _padata): - as_rep_usage = KU_AS_REP_ENC_PART - return preauth_key, as_rep_usage - pac_options = kdc_dict.pop('pac_options', '1') # claims support kdc_options = kdc_dict.pop('kdc_options', kdc_options_default) @@ -1274,11 +1264,6 @@ class FAST_Tests(KDCBaseTest): preauth_key = None padata = [] - if rep_type == KRB_AS_REP: - check_padata_fn = _check_padata_preauth_key - else: - check_padata_fn = self.check_simple_tgs_padata - if use_fast: inner_padata = padata outer_padata = [] @@ -1332,13 +1317,13 @@ class FAST_Tests(KDCBaseTest): generate_padata_fn=generate_padata_fn, check_error_fn=check_error_fn, check_rep_fn=check_rep_fn, - check_padata_fn=check_padata_fn, check_kdc_private_fn=self.generic_check_kdc_private, callback_dict={}, expected_error_mode=expected_error_mode, client_as_etypes=etypes, expected_salt=expected_salt, authenticator_subkey=authenticator_subkey, + preauth_key=preauth_key, auth_data=auth_data, armor_key=armor_key, armor_tgt=armor_tgt, @@ -1365,7 +1350,6 @@ class FAST_Tests(KDCBaseTest): generate_padata_fn=generate_padata_fn, check_error_fn=check_error_fn, check_rep_fn=check_rep_fn, - check_padata_fn=check_padata_fn, check_kdc_private_fn=self.generic_check_kdc_private, expected_error_mode=expected_error_mode, callback_dict={}, diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index f65811243ba..164d06b9788 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1794,7 +1794,6 @@ class RawKerberosTest(TestCaseInTempDir): generate_padata_fn=None, check_error_fn=None, check_rep_fn=None, - check_padata_fn=None, check_kdc_private_fn=None, callback_dict=None, expected_error_mode=0, @@ -1802,6 +1801,7 @@ class RawKerberosTest(TestCaseInTempDir): client_as_etypes=None, expected_salt=None, authenticator_subkey=None, + preauth_key=None, armor_key=None, armor_tgt=None, armor_subkey=None, @@ -1838,7 +1838,6 @@ class RawKerberosTest(TestCaseInTempDir): 'generate_padata_fn': generate_padata_fn, 'check_error_fn': check_error_fn, 'check_rep_fn': check_rep_fn, - 'check_padata_fn': check_padata_fn, 'check_kdc_private_fn': check_kdc_private_fn, 'callback_dict': callback_dict, 'expected_error_mode': expected_error_mode, @@ -1846,6 +1845,7 @@ class RawKerberosTest(TestCaseInTempDir): 'client_as_etypes': client_as_etypes, 'expected_salt': expected_salt, 'authenticator_subkey': authenticator_subkey, + 'preauth_key': preauth_key, 'armor_key': armor_key, 'armor_tgt': armor_tgt, 'armor_subkey': armor_subkey, @@ -1878,7 +1878,6 @@ class RawKerberosTest(TestCaseInTempDir): generate_padata_fn=None, check_error_fn=None, check_rep_fn=None, - check_padata_fn=None, check_kdc_private_fn=None, expected_error_mode=0, expected_status=None, @@ -1922,7 +1921,6 @@ class RawKerberosTest(TestCaseInTempDir): 'generate_padata_fn': generate_padata_fn, 'check_error_fn': check_error_fn, 'check_rep_fn': check_rep_fn, - 'check_padata_fn': check_padata_fn, 'check_kdc_private_fn': check_kdc_private_fn, 'callback_dict': callback_dict, 'expected_error_mode': expected_error_mode, @@ -1956,7 +1954,6 @@ class RawKerberosTest(TestCaseInTempDir): expected_srealm = kdc_exchange_dict['expected_srealm'] expected_sname = kdc_exchange_dict['expected_sname'] ticket_decryption_key = kdc_exchange_dict['ticket_decryption_key'] - check_padata_fn = kdc_exchange_dict['check_padata_fn'] check_kdc_private_fn = kdc_exchange_dict['check_kdc_private_fn'] rep_encpart_asn1Spec = kdc_exchange_dict['rep_encpart_asn1Spec'] msg_type = kdc_exchange_dict['rep_msg_type'] @@ -2004,41 +2001,37 @@ class RawKerberosTest(TestCaseInTempDir): ticket_checksum = None - encpart_decryption_key = None - self.assertIsNotNone(check_padata_fn) - if check_padata_fn is not None: - # See if we can get the decryption key from the preauth phase - encpart_decryption_key, encpart_decryption_usage = ( - check_padata_fn(kdc_exchange_dict, callback_dict, - rep, padata)) - - if armor_key is not None: - pa_dict = self.get_pa_dict(padata) - - if PADATA_FX_FAST in pa_dict: - fx_fast_data = pa_dict[PADATA_FX_FAST] - fast_response = self.check_fx_fast_data(kdc_exchange_dict, - fx_fast_data, - armor_key, - finished=True) - - if 'strengthen-key' in fast_response: - strengthen_key = self.EncryptionKey_import( - fast_response['strengthen-key']) - encpart_decryption_key = ( - self.generate_strengthen_reply_key( - strengthen_key, - encpart_decryption_key)) - - fast_finished = fast_response.get('finished', None) - if fast_finished is not None: - ticket_checksum = fast_finished['ticket-checksum'] - - self.check_rep_padata(kdc_exchange_dict, - callback_dict, - rep, - fast_response['padata'], - error_code=0) + # Get the decryption key for the encrypted part + encpart_decryption_key, encpart_decryption_usage = ( + self.get_preauth_key(kdc_exchange_dict)) + + if armor_key is not None: + pa_dict = self.get_pa_dict(padata) + + if PADATA_FX_FAST in pa_dict: + fx_fast_data = pa_dict[PADATA_FX_FAST] + fast_response = self.check_fx_fast_data(kdc_exchange_dict, + fx_fast_data, + armor_key, + finished=True) + + if 'strengthen-key' in fast_response: + strengthen_key = self.EncryptionKey_import( + fast_response['strengthen-key']) + encpart_decryption_key = ( + self.generate_strengthen_reply_key( + strengthen_key, + encpart_decryption_key)) + + fast_finished = fast_response.get('finished') + if fast_finished is not None: + ticket_checksum = fast_finished['ticket-checksum'] + + self.check_rep_padata(kdc_exchange_dict, + callback_dict, + rep, + fast_response['padata'], + error_code=0) ticket_private = None self.assertIsNotNone(ticket_decryption_key) @@ -2558,13 +2551,7 @@ class RawKerberosTest(TestCaseInTempDir): armor_key = kdc_exchange_dict['armor_key'] self.assertIsNotNone(armor_key) - check_padata_fn = kdc_exchange_dict['check_padata_fn'] - padata = self.getElementValue(rep, 'padata') - self.assertIsNotNone(check_padata_fn) - preauth_key, _ = check_padata_fn(kdc_exchange_dict, - callback_dict, - rep, - padata) + preauth_key, _ = self.get_preauth_key(kdc_exchange_dict) kdc_challenge_key = self.generate_kdc_challenge_key( armor_key, preauth_key) @@ -2790,21 +2777,25 @@ class RawKerberosTest(TestCaseInTempDir): return padata, req_body - def check_simple_tgs_padata(self, - kdc_exchange_dict, - callback_dict, - rep, - padata): - tgt = kdc_exchange_dict['tgt'] - authenticator_subkey = kdc_exchange_dict['authenticator_subkey'] - if authenticator_subkey is not None: - subkey = authenticator_subkey - subkey_usage = KU_TGS_REP_ENC_PART_SUB_KEY - else: - subkey = tgt.session_key - subkey_usage = KU_TGS_REP_ENC_PART_SESSION + def get_preauth_key(self, kdc_exchange_dict): + msg_type = kdc_exchange_dict['rep_msg_type'] + + if msg_type == KRB_AS_REP: + key = kdc_exchange_dict['preauth_key'] + usage = KU_AS_REP_ENC_PART + else: # KRB_TGS_REP + authenticator_subkey = kdc_exchange_dict['authenticator_subkey'] + if authenticator_subkey is not None: + key = authenticator_subkey + usage = KU_TGS_REP_ENC_PART_SUB_KEY + else: + tgt = kdc_exchange_dict['tgt'] + key = tgt.session_key + usage = KU_TGS_REP_ENC_PART_SESSION + + self.assertIsNotNone(key) - return subkey, subkey_usage + return key, usage def generate_armor_key(self, subkey, session_key): armor_key = kcrypto.cf2(subkey.key, @@ -2926,13 +2917,6 @@ class RawKerberosTest(TestCaseInTempDir): req_body): return padata, req_body - def _check_padata_preauth_key(_kdc_exchange_dict, - _callback_dict, - rep, - padata): - as_rep_usage = KU_AS_REP_ENC_PART - return preauth_key, as_rep_usage - if not expected_error_mode: check_error_fn = None check_rep_fn = self.generic_check_kdc_rep @@ -2954,13 +2938,13 @@ class RawKerberosTest(TestCaseInTempDir): generate_padata_fn=generate_padata_fn, check_error_fn=check_error_fn, check_rep_fn=check_rep_fn, - check_padata_fn=_check_padata_preauth_key, check_kdc_private_fn=self.generic_check_kdc_private, expected_error_mode=expected_error_mode, client_as_etypes=client_as_etypes, expected_salt=expected_salt, expected_flags=expected_flags, unexpected_flags=unexpected_flags, + preauth_key=preauth_key, kdc_options=str(kdc_options), pac_request=pac_request, pac_options=pac_options, -- 2.25.1 From 8799fd322a9f4127504ead5d8dc79aae0bdb923d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 3 Sep 2021 15:36:24 +1200 Subject: [PATCH 030/162] tests/krb5: Add get_cached_creds() method to create persistent accounts for testing BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit c9fd8ffd8927ef42fd555e690f966f65aa01332e) --- python/samba/tests/krb5/fast_tests.py | 2 +- python/samba/tests/krb5/kdc_base_test.py | 191 +++++++++++++++-------- 2 files changed, 125 insertions(+), 68 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 12235cd439e..106b9b1fb78 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1108,7 +1108,7 @@ class FAST_Tests(KDCBaseTest): target_sname = self.PrincipalName_create( name_type=NT_SRV_INST, names=[target_service, target_username]) target_decryption_key = self.TicketDecryptionKey_from_creds( - target_creds, etype=kcrypto.Enctype.RC4) + target_creds) fast_cookie = None preauth_etype_info2 = None diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 49a3227c26e..b2b9d87c3af 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -22,6 +22,7 @@ from datetime import datetime, timezone import tempfile import binascii import collections +import secrets from collections import namedtuple import ldb @@ -37,7 +38,10 @@ from samba.dsdb import ( DS_GUID_COMPUTERS_CONTAINER, DS_GUID_USERS_CONTAINER, UF_WORKSTATION_TRUST_ACCOUNT, - UF_NORMAL_ACCOUNT + UF_NO_AUTH_DATA_REQUIRED, + UF_NORMAL_ACCOUNT, + UF_NOT_DELEGATED, + UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION ) from samba.ndr import ndr_pack, ndr_unpack from samba import net @@ -88,9 +92,17 @@ class KDCBaseTest(RawKerberosTest): cls._functional_level = None + # An identifier to ensure created accounts have unique names. Windows + # caches accounts based on usernames, so account names being different + # across test runs avoids previous test runs affecting the results. + cls.account_base = f'krb5_{secrets.token_hex(5)}_' + cls.account_id = 0 + # A set containing DNs of accounts created as part of testing. cls.accounts = set() + cls.account_cache = {} + @classmethod def tearDownClass(cls): # Clean up any accounts created by create_account. This is @@ -322,24 +334,113 @@ class KDCBaseTest(RawKerberosTest): creds.set_tgs_supported_enctypes(supported_enctypes) creds.set_ap_supported_enctypes(supported_enctypes) - def get_client_creds(self, - allow_missing_password=False, - allow_missing_keys=True): - def create_client_account(): - samdb = self.get_samdb() + def get_cached_creds(self, *, + machine_account, + opts=None): + if opts is None: + opts = {} + + opts_default = { + 'no_auth_data_required': False, + 'supported_enctypes': None, + 'not_delegated': False, + 'allowed_to_delegate_to': None, + 'trusted_to_auth_for_delegation': False, + 'fast_support': False + } + + account_opts = { + 'machine_account': machine_account, + **opts_default, + **opts + } + + cache_key = tuple(sorted(account_opts.items())) + + creds = self.account_cache.get(cache_key) + if creds is None: + creds = self.create_account_opts(**account_opts) + self.account_cache[cache_key] = creds + + return creds + + def create_account_opts(self, *, + machine_account, + no_auth_data_required, + supported_enctypes, + not_delegated, + allowed_to_delegate_to, + trusted_to_auth_for_delegation, + fast_support): + if machine_account: + self.assertFalse(not_delegated) + else: + self.assertIsNone(allowed_to_delegate_to) + self.assertFalse(trusted_to_auth_for_delegation) - creds, dn = self.create_account(samdb, 'kdctestclient') + samdb = self.get_samdb() - res = samdb.search(base=dn, - scope=ldb.SCOPE_BASE, - attrs=['msDS-KeyVersionNumber']) - kvno = int(res[0]['msDS-KeyVersionNumber'][0]) - creds.set_kvno(kvno) + user_name = self.account_base + str(self.account_id) + type(self).account_id += 1 - keys = self.get_keys(samdb, dn) - self.creds_set_keys(creds, keys) + user_account_control = 0 + if trusted_to_auth_for_delegation: + user_account_control |= UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION + if not_delegated: + user_account_control |= UF_NOT_DELEGATED + if no_auth_data_required: + user_account_control |= UF_NO_AUTH_DATA_REQUIRED - return creds + details = {} + + enctypes = supported_enctypes + if fast_support: + fast_bits = (security.KERB_ENCTYPE_FAST_SUPPORTED | + security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED | + security.KERB_ENCTYPE_CLAIMS_SUPPORTED) + enctypes = (enctypes or 0) | fast_bits + + if enctypes is not None: + details['msDS-SupportedEncryptionTypes'] = str(enctypes) + + if allowed_to_delegate_to: + details['msDS-AllowedToDelegateTo'] = allowed_to_delegate_to + + if machine_account: + spn = 'host/' + user_name + else: + spn = None + + creds, dn = self.create_account(samdb, user_name, + machine_account=machine_account, + spn=spn, + additional_details=details, + account_control=user_account_control) + + res = samdb.search(base=dn, + scope=ldb.SCOPE_BASE, + attrs=['msDS-KeyVersionNumber']) + kvno = int(res[0]['msDS-KeyVersionNumber'][0]) + creds.set_kvno(kvno) + + keys = self.get_keys(samdb, dn) + self.creds_set_keys(creds, keys) + + if machine_account: + if supported_enctypes is not None: + tgs_enctypes = supported_enctypes + else: + tgs_enctypes = security.KERB_ENCTYPE_RC4_HMAC_MD5 + + creds.set_tgs_supported_enctypes(tgs_enctypes) + + return creds + + def get_client_creds(self, + allow_missing_password=False, + allow_missing_keys=True): + def create_client_account(): + return self.get_cached_creds(machine_account=False) c = self._get_krb5_creds(prefix='CLIENT', allow_missing_password=allow_missing_password, @@ -351,32 +452,8 @@ class KDCBaseTest(RawKerberosTest): allow_missing_password=False, allow_missing_keys=True): def create_mach_account(): - samdb = self.get_samdb() - - mach_name = 'kdctestmac' - details = { - 'msDS-SupportedEncryptionTypes': str( - security.KERB_ENCTYPE_FAST_SUPPORTED | - security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED | - security.KERB_ENCTYPE_CLAIMS_SUPPORTED - ) - } - - creds, dn = self.create_account(samdb, mach_name, - machine_account=True, - spn='host/' + mach_name, - additional_details=details) - - res = samdb.search(base=dn, - scope=ldb.SCOPE_BASE, - attrs=['msDS-KeyVersionNumber']) - kvno = int(res[0]['msDS-KeyVersionNumber'][0]) - creds.set_kvno(kvno) - - keys = self.get_keys(samdb, dn) - self.creds_set_keys(creds, keys) - - return creds + return self.get_cached_creds(machine_account=True, + opts={'fast_support': True}) c = self._get_krb5_creds(prefix='MAC', allow_missing_password=allow_missing_password, @@ -388,32 +465,12 @@ class KDCBaseTest(RawKerberosTest): allow_missing_password=False, allow_missing_keys=True): def create_service_account(): - samdb = self.get_samdb() - - mach_name = 'kdctestservice' - details = { - 'msDS-SupportedEncryptionTypes': str( - security.KERB_ENCTYPE_FAST_SUPPORTED | - security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED | - security.KERB_ENCTYPE_CLAIMS_SUPPORTED - ) - } - - creds, dn = self.create_account(samdb, mach_name, - machine_account=True, - spn='host/' + mach_name, - additional_details=details) - - res = samdb.search(base=dn, - scope=ldb.SCOPE_BASE, - attrs=['msDS-KeyVersionNumber']) - kvno = int(res[0]['msDS-KeyVersionNumber'][0]) - creds.set_kvno(kvno) - - keys = self.get_keys(samdb, dn) - self.creds_set_keys(creds, keys) - - return creds + return self.get_cached_creds( + machine_account=True, + opts={ + 'trusted_to_auth_for_delegation': True, + 'fast_support': True + }) c = self._get_krb5_creds(prefix='SERVICE', allow_missing_password=allow_missing_password, -- 2.25.1 From 73990804097d4efdca751e91cc3213bf6d5be0df Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 8 Sep 2021 11:28:52 +1200 Subject: [PATCH 031/162] tests/krb5: Generate padata for FAST tests This gives us access to parameters of kdc_exchange_dict and enables us to simplify the logic. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit 943079fd94fec66cdc2ba4ea1b2beb2971473004) --- python/samba/tests/krb5/fast_tests.py | 101 ++++++++++++++++---------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 106b9b1fb78..8024b92f445 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1017,19 +1017,6 @@ class FAST_Tests(KDCBaseTest): # challenge is only considered a replay if the ciphertext is identical # to a previous challenge. Windows does not perform this check. - class GenerateEncChallengePadataReplay: - def __init__(replay): - replay._padata = None - - def __call__(replay, key, armor_key): - if replay._padata is None: - client_challenge_key = ( - self.generate_client_challenge_key(armor_key, key)) - replay._padata = self.get_challenge_pa_data( - client_challenge_key) - - return replay._padata - self._run_test_sequence([ { 'rep_type': KRB_AS_REP, @@ -1042,28 +1029,72 @@ class FAST_Tests(KDCBaseTest): 'rep_type': KRB_AS_REP, 'expected_error_mode': 0, 'use_fast': True, - 'gen_padata_fn': GenerateEncChallengePadataReplay(), + 'gen_padata_fn': self.generate_enc_challenge_padata_replay, 'fast_armor': FX_FAST_ARMOR_AP_REQUEST, 'gen_armor_tgt_fn': self.get_mach_tgt, 'repeat': 2 } ]) - def generate_enc_timestamp_padata(self, key, _armor_key): - return self.get_enc_timestamp_pa_data_from_key(key) + def generate_enc_timestamp_padata(self, + kdc_exchange_dict, + callback_dict, + req_body): + key = kdc_exchange_dict['preauth_key'] + + padata = self.get_enc_timestamp_pa_data_from_key(key) + return [padata], req_body + + def generate_enc_challenge_padata(self, + kdc_exchange_dict, + callback_dict, + req_body, + skew=0): + armor_key = kdc_exchange_dict['armor_key'] + key = kdc_exchange_dict['preauth_key'] - def generate_enc_challenge_padata(self, key, armor_key, skew=0): client_challenge_key = ( self.generate_client_challenge_key(armor_key, key)) - return self.get_challenge_pa_data(client_challenge_key, skew=skew) + padata = self.get_challenge_pa_data(client_challenge_key, skew=skew) + return [padata], req_body + + def generate_enc_challenge_padata_wrong_key_kdc(self, + kdc_exchange_dict, + callback_dict, + req_body): + armor_key = kdc_exchange_dict['armor_key'] + key = kdc_exchange_dict['preauth_key'] - def generate_enc_challenge_padata_wrong_key_kdc(self, key, armor_key): kdc_challenge_key = ( self.generate_kdc_challenge_key(armor_key, key)) - return self.get_challenge_pa_data(kdc_challenge_key) + padata = self.get_challenge_pa_data(kdc_challenge_key) + return [padata], req_body - def generate_enc_challenge_padata_wrong_key(self, key, _armor_key): - return self.get_challenge_pa_data(key) + def generate_enc_challenge_padata_wrong_key(self, + kdc_exchange_dict, + callback_dict, + req_body): + key = kdc_exchange_dict['preauth_key'] + + padata = self.get_challenge_pa_data(key) + return [padata], req_body + + def generate_enc_challenge_padata_replay(self, + kdc_exchange_dict, + callback_dict, + req_body): + padata = callback_dict.get('replay_padata') + + if padata is None: + armor_key = kdc_exchange_dict['armor_key'] + key = kdc_exchange_dict['preauth_key'] + + client_challenge_key = ( + self.generate_client_challenge_key(armor_key, key)) + padata = self.get_challenge_pa_data(client_challenge_key) + callback_dict['replay_padata'] = padata + + return [padata], req_body def generate_empty_fast(self, _kdc_exchange_dict, @@ -1251,35 +1282,25 @@ class FAST_Tests(KDCBaseTest): kdc_options = kdc_dict.pop('kdc_options', kdc_options_default) gen_padata_fn = kdc_dict.pop('gen_padata_fn', None) - if gen_padata_fn is not None: - self.assertEqual(KRB_AS_REP, rep_type) + + if rep_type == KRB_AS_REP and gen_padata_fn is not None: self.assertIsNotNone(preauth_etype_info2) preauth_key = self.PasswordKey_from_etype_info2( client_creds, preauth_etype_info2[0], client_creds.get_kvno()) - padata = [gen_padata_fn(preauth_key, armor_key)] else: preauth_key = None - padata = [] if use_fast: - inner_padata = padata - outer_padata = [] + generate_fast_padata_fn = gen_padata_fn + generate_padata_fn = (functools.partial(_generate_padata_copy, + padata=[fast_cookie]) + if fast_cookie is not None else None) else: - inner_padata = [] - outer_padata = padata - - if use_fast and fast_cookie is not None: - outer_padata.append(fast_cookie) - - generate_fast_padata_fn = (functools.partial(_generate_padata_copy, - padata=inner_padata) - if inner_padata else None) - generate_padata_fn = (functools.partial(_generate_padata_copy, - padata=outer_padata) - if outer_padata else None) + generate_fast_padata_fn = None + generate_padata_fn = gen_padata_fn gen_authdata_fn = kdc_dict.pop('gen_authdata_fn', None) if gen_authdata_fn is not None: -- 2.25.1 From da9144b8aaa815ee60b8e9ffdef599cca53e8e68 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 13 Sep 2021 21:14:18 +1200 Subject: [PATCH 032/162] tests/krb5: Sign-extend kvno from 32-bit integer This helps to avoid problems with RODC kvnos that have the high bit set. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit 7bc52cecb442c4bcbd39372a8b98bb033e4d1540) --- python/samba/tests/krb5/raw_testcase.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 164d06b9788..cca38fb9480 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -294,6 +294,9 @@ class KerberosCredentials(Credentials): return self._get_krb5_etypes(self.ap_supported_enctypes) def set_kvno(self, kvno): + # Sign-extend from 32 bits. + if kvno & 1 << 31: + kvno |= -1 << 31 self.kvno = kvno def get_kvno(self): -- 2.25.1 From 53c3d8ebc0c13d19fe64d846614c0e22ae207bb3 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 13 Sep 2021 20:20:23 +1200 Subject: [PATCH 033/162] tests/krb5: Add method to get RODC krbtgt credentials BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit a5bf7aad54b7053417a24ae0918ee42ceed7bf21) --- python/samba/tests/krb5/kdc_base_test.py | 74 ++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index b2b9d87c3af..fd2e4d08cd3 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -89,6 +89,7 @@ class KDCBaseTest(RawKerberosTest): cls._lp = None cls._ldb = None + cls._rodc_ldb = None cls._functional_level = None @@ -137,6 +138,30 @@ class KDCBaseTest(RawKerberosTest): return self._ldb + def get_rodc_samdb(self): + if self._rodc_ldb is None: + creds = self.get_admin_creds() + lp = self.get_lp() + + session = system_session() + type(self)._rodc_ldb = SamDB(url="ldap://%s" % self.host, + session_info=session, + credentials=creds, + lp=lp, + am_rodc=True) + + return self._rodc_ldb + + def get_server_dn(self, samdb): + server = samdb.get_serverName() + + res = samdb.search(base=server, + scope=ldb.SCOPE_BASE, + attrs=['serverReference']) + dn = ldb.Dn(samdb, res[0]['serverReference'][0].decode('utf8')) + + return dn + def get_domain_functional_level(self, ldb): if self._functional_level is None: res = ldb.search(base='', @@ -478,6 +503,55 @@ class KDCBaseTest(RawKerberosTest): fallback_creds_fn=create_service_account) return c + def get_rodc_krbtgt_creds(self, + require_keys=True, + require_strongest_key=False): + if require_strongest_key: + self.assertTrue(require_keys) + + def download_rodc_krbtgt_creds(): + samdb = self.get_samdb() + rodc_samdb = self.get_rodc_samdb() + + rodc_dn = self.get_server_dn(rodc_samdb) + + res = samdb.search(rodc_dn, + scope=ldb.SCOPE_BASE, + attrs=['msDS-KrbTgtLink']) + krbtgt_dn = res[0]['msDS-KrbTgtLink'][0] + + res = samdb.search(krbtgt_dn, + scope=ldb.SCOPE_BASE, + attrs=['sAMAccountName', + 'msDS-KeyVersionNumber', + 'msDS-SecondaryKrbTgtNumber']) + krbtgt_dn = res[0].dn + username = str(res[0]['sAMAccountName']) + + creds = KerberosCredentials() + creds.set_domain(self.env_get_var('DOMAIN', 'RODC_KRBTGT')) + creds.set_realm(self.env_get_var('REALM', 'RODC_KRBTGT')) + creds.set_username(username) + + kvno = int(res[0]['msDS-KeyVersionNumber'][0]) + krbtgt_number = int(res[0]['msDS-SecondaryKrbTgtNumber'][0]) + + rodc_kvno = krbtgt_number << 16 | kvno + creds.set_kvno(rodc_kvno) + creds.set_dn(krbtgt_dn) + + keys = self.get_keys(samdb, krbtgt_dn) + self.creds_set_keys(creds, keys) + + return creds + + c = self._get_krb5_creds(prefix='RODC_KRBTGT', + allow_missing_password=True, + allow_missing_keys=not require_keys, + require_strongest_key=require_strongest_key, + fallback_creds_fn=download_rodc_krbtgt_creds) + return c + def get_krbtgt_creds(self, require_keys=True, require_strongest_key=False): -- 2.25.1 From 5dc89d29003bfa015a4bbedca1ac5c4f90256db7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 13 Sep 2021 20:58:01 +1200 Subject: [PATCH 034/162] tests/krb5: Add get_secrets() method to get the secret attributes of a DN BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit af633992e31e839cdd7f77740c1f25d129be2f79) --- python/samba/tests/krb5/kdc_base_test.py | 26 +++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index fd2e4d08cd3..3681d26bb83 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -250,7 +250,9 @@ class KDCBaseTest(RawKerberosTest): return (creds, dn) - def get_keys(self, samdb, dn): + def get_secrets(self, samdb, dn, + destination_dsa_guid, + source_dsa_invocation_id): admin_creds = self.get_admin_creds() dns_hostname = samdb.host_dns_name() @@ -258,15 +260,13 @@ class KDCBaseTest(RawKerberosTest): self.get_lp(), admin_creds) - destination_dsa_guid = misc.GUID(samdb.get_ntds_GUID()) - req = drsuapi.DsGetNCChangesRequest8() req.destination_dsa_guid = destination_dsa_guid - req.source_dsa_invocation_id = misc.GUID() + req.source_dsa_invocation_id = source_dsa_invocation_id naming_context = drsuapi.DsReplicaObjectIdentifier() - naming_context.dn = str(dn) + naming_context.dn = dn req.naming_context = naming_context @@ -299,9 +299,25 @@ class KDCBaseTest(RawKerberosTest): req.mapping_ctr.mappings = None _, ctr = bind.DsGetNCChanges(handle, 8, req) + + self.assertEqual(1, ctr.object_count) + identifier = ctr.first_object.object.identifier attributes = ctr.first_object.object.attribute_ctr.attributes + self.assertEqual(dn, identifier.dn) + + return bind, identifier, attributes + + def get_keys(self, samdb, dn): + admin_creds = self.get_admin_creds() + + bind, identifier, attributes = self.get_secrets( + samdb, + str(dn), + destination_dsa_guid=misc.GUID(samdb.get_ntds_GUID()), + source_dsa_invocation_id=misc.GUID()) + rid = identifier.sid.split()[1] net_ctx = net.Net(admin_creds) -- 2.25.1 From 1d552860666e676e4615ca063e11cefa70a3ae4a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 13 Sep 2021 22:13:24 +1200 Subject: [PATCH 035/162] tests/krb5: Allow replicating accounts to the RODC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit 3cc9e77f38f6698aa01abca4285a520c7c0cd2ac) --- python/samba/tests/krb5/kdc_base_test.py | 141 ++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 3681d26bb83..56102cfc4ea 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -31,8 +31,9 @@ from samba import generate_random_password from samba.auth import system_session from samba.credentials import Credentials, SPECIFIED, MUST_USE_KERBEROS from samba.dcerpc import drsblobs, drsuapi, misc, krb5pac, krb5ccache, security -from samba.drs_utils import drsuapi_connect +from samba.drs_utils import drs_Replicate, drsuapi_connect from samba.dsdb import ( + DSDB_SYNTAX_BINARY_DN, DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2008, DS_GUID_COMPUTERS_CONTAINER, @@ -45,7 +46,7 @@ from samba.dsdb import ( ) from samba.ndr import ndr_pack, ndr_unpack from samba import net -from samba.samdb import SamDB +from samba.samdb import SamDB, dsdb_Dn from samba.tests import delete_force import samba.tests.krb5.kcrypto as kcrypto @@ -104,12 +105,20 @@ class KDCBaseTest(RawKerberosTest): cls.account_cache = {} + cls.ldb_cleanups = [] + @classmethod def tearDownClass(cls): # Clean up any accounts created by create_account. This is # done in tearDownClass() rather than tearDown(), so that # accounts need only be created once for permutation tests. if cls._ldb is not None: + for cleanup in reversed(cls.ldb_cleanups): + try: + cls._ldb.modify(cleanup) + except ldb.LdbError: + pass + for dn in cls.accounts: delete_force(cls._ldb, dn) super().tearDownClass() @@ -250,6 +259,76 @@ class KDCBaseTest(RawKerberosTest): return (creds, dn) + def replicate_account_to_rodc(self, dn): + samdb = self.get_samdb() + rodc_samdb = self.get_rodc_samdb() + + repl_val = f'{samdb.get_dsServiceName()}:{dn}:SECRETS_ONLY' + + msg = ldb.Message() + msg.dn = ldb.Dn(rodc_samdb, '') + msg['replicateSingleObject'] = ldb.MessageElement( + repl_val, + ldb.FLAG_MOD_REPLACE, + 'replicateSingleObject') + + try: + # Try replication using the replicateSingleObject rootDSE + # operation. + rodc_samdb.modify(msg) + except ldb.LdbError as err: + enum, estr = err.args + self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) + self.assertIn('rootdse_modify: unknown attribute to change!', + estr) + + # If that method wasn't supported, we may be in the rodc:local test + # environment, where we can try replicating to the local database. + + lp = self.get_lp() + + rodc_creds = Credentials() + rodc_creds.guess(lp) + rodc_creds.set_machine_account(lp) + + local_samdb = SamDB(url=None, session_info=system_session(), + credentials=rodc_creds, lp=lp) + + destination_dsa_guid = misc.GUID(local_samdb.get_ntds_GUID()) + + repl = drs_Replicate(f'ncacn_ip_tcp:{self.dc_host}[seal]', + lp, rodc_creds, + local_samdb, destination_dsa_guid) + + source_dsa_invocation_id = misc.GUID(samdb.invocation_id) + + repl.replicate(dn, + source_dsa_invocation_id, + destination_dsa_guid, + exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, + rodc=True) + + def check_revealed(self, dn, rodc_dn, revealed=True): + samdb = self.get_samdb() + + res = samdb.search(base=rodc_dn, + scope=ldb.SCOPE_BASE, + attrs=['msDS-RevealedUsers']) + + revealed_users = res[0].get('msDS-RevealedUsers') + if revealed_users is None: + self.assertFalse(revealed) + return + + revealed_dns = set(str(dsdb_Dn(samdb, str(user), + syntax_oid=DSDB_SYNTAX_BINARY_DN).dn) + for user in revealed_users) + + if revealed: + self.assertIn(str(dn), revealed_dns) + else: + self.assertNotIn(str(dn), revealed_dns) + def get_secrets(self, samdb, dn, destination_dsa_guid, source_dsa_invocation_id): @@ -375,6 +454,29 @@ class KDCBaseTest(RawKerberosTest): creds.set_tgs_supported_enctypes(supported_enctypes) creds.set_ap_supported_enctypes(supported_enctypes) + def add_to_group(self, account_dn, group_dn, group_attr): + samdb = self.get_samdb() + + res = samdb.search(base=group_dn, + scope=ldb.SCOPE_BASE, + attrs=[group_attr]) + orig_msg = res[0] + + members = list(orig_msg[group_attr]) + members.append(account_dn) + + msg = ldb.Message() + msg.dn = group_dn + msg[group_attr] = ldb.MessageElement(members, + ldb.FLAG_MOD_REPLACE, + group_attr) + + cleanup = samdb.msg_diff(msg, orig_msg) + self.ldb_cleanups.append(cleanup) + samdb.modify(msg) + + return cleanup + def get_cached_creds(self, *, machine_account, opts=None): @@ -382,6 +484,9 @@ class KDCBaseTest(RawKerberosTest): opts = {} opts_default = { + 'allowed_replication': False, + 'denied_replication': False, + 'revealed_to_rodc': False, 'no_auth_data_required': False, 'supported_enctypes': None, 'not_delegated': False, @@ -407,6 +512,9 @@ class KDCBaseTest(RawKerberosTest): def create_account_opts(self, *, machine_account, + allowed_replication, + denied_replication, + revealed_to_rodc, no_auth_data_required, supported_enctypes, not_delegated, @@ -420,6 +528,9 @@ class KDCBaseTest(RawKerberosTest): self.assertFalse(trusted_to_auth_for_delegation) samdb = self.get_samdb() + rodc_samdb = self.get_rodc_samdb() + + rodc_dn = self.get_server_dn(rodc_samdb) user_name = self.account_base + str(self.account_id) type(self).account_id += 1 @@ -475,6 +586,32 @@ class KDCBaseTest(RawKerberosTest): creds.set_tgs_supported_enctypes(tgs_enctypes) + # Handle secret replication to the RODC. + + if allowed_replication or revealed_to_rodc: + # Allow replicating this account's secrets if requested, or allow + # it only temporarily if we're about to replicate them. + allowed_cleanup = self.add_to_group( + dn, rodc_dn, + 'msDS-RevealOnDemandGroup') + + if revealed_to_rodc: + # Replicate this account's secrets to the RODC. + self.replicate_account_to_rodc(dn) + + if not allowed_replication: + # If we don't want replicating secrets to be allowed for this + # account, disable it again. + samdb.modify(allowed_cleanup) + + self.check_revealed(dn, + rodc_dn, + revealed=revealed_to_rodc) + + if denied_replication: + # Deny replicating this account's secrets to the RODC. + self.add_to_group(dn, rodc_dn, 'msDS-NeverRevealGroup') + return creds def get_client_creds(self, -- 2.25.1 From 2a6990948b7d5efafc14bdc11751002c0a7f2e51 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 13 Sep 2021 21:24:05 +1200 Subject: [PATCH 036/162] tests/krb5: Create RODC account for testing BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit ef5666bc51ca80e1acdadd525a9c61762756c8e3) --- python/samba/tests/krb5/kdc_base_test.py | 114 +++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 56102cfc4ea..892d3aaf41f 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -42,8 +42,10 @@ from samba.dsdb import ( UF_NO_AUTH_DATA_REQUIRED, UF_NORMAL_ACCOUNT, UF_NOT_DELEGATED, + UF_PARTIAL_SECRETS_ACCOUNT, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION ) +from samba.join import DCJoinContext from samba.ndr import ndr_pack, ndr_unpack from samba import net from samba.samdb import SamDB, dsdb_Dn @@ -105,6 +107,8 @@ class KDCBaseTest(RawKerberosTest): cls.account_cache = {} + cls._rodc_ctx = None + cls.ldb_cleanups = [] @classmethod @@ -121,6 +125,10 @@ class KDCBaseTest(RawKerberosTest): for dn in cls.accounts: delete_force(cls._ldb, dn) + + if cls._rodc_ctx is not None: + cls._rodc_ctx.cleanup_old_join(force=True) + super().tearDownClass() def setUp(self): @@ -171,6 +179,25 @@ class KDCBaseTest(RawKerberosTest): return dn + def get_mock_rodc_ctx(self): + if self._rodc_ctx is None: + admin_creds = self.get_admin_creds() + lp = self.get_lp() + + rodc_name = 'KRB5RODC' + site_name = 'Default-First-Site-Name' + + type(self)._rodc_ctx = DCJoinContext(server=self.dc_host, + creds=admin_creds, + lp=lp, + site=site_name, + netbios_name=rodc_name, + targetdir=None, + domain=None) + self.create_rodc(self._rodc_ctx) + + return self._rodc_ctx + def get_domain_functional_level(self, ldb): if self._functional_level is None: res = ldb.search(base='', @@ -259,6 +286,49 @@ class KDCBaseTest(RawKerberosTest): return (creds, dn) + def create_rodc(self, ctx): + ctx.nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn] + ctx.full_nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn] + ctx.krbtgt_dn = f'CN=krbtgt_{ctx.myname},CN=Users,{ctx.base_dn}' + + ctx.never_reveal_sid = [f'', + f'', + f'', + f'', + f''] + ctx.reveal_sid = f'' + + mysid = ctx.get_mysid() + admin_dn = f'' + ctx.managedby = admin_dn + + ctx.userAccountControl = (UF_WORKSTATION_TRUST_ACCOUNT | + UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION | + UF_PARTIAL_SECRETS_ACCOUNT) + + ctx.connection_dn = f'CN=RODC Connection (FRS),{ctx.ntds_dn}' + ctx.secure_channel_type = misc.SEC_CHAN_RODC + ctx.RODC = True + ctx.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC | + drsuapi.DRSUAPI_DRS_PER_SYNC | + drsuapi.DRSUAPI_DRS_GET_ANC | + drsuapi.DRSUAPI_DRS_NEVER_SYNCED | + drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) + ctx.domain_replica_flags = ctx.replica_flags | drsuapi.DRSUAPI_DRS_CRITICAL_ONLY + + ctx.build_nc_lists() + + ctx.cleanup_old_join() + + try: + ctx.join_add_objects() + except Exception: + # cleanup the failed join (checking we still have a live LDB + # connection to the remote DC first) + ctx.refresh_ldb_connection() + ctx.cleanup_old_join() + raise + def replicate_account_to_rodc(self, dn): samdb = self.get_samdb() rodc_samdb = self.get_rodc_samdb() @@ -705,6 +775,50 @@ class KDCBaseTest(RawKerberosTest): fallback_creds_fn=download_rodc_krbtgt_creds) return c + def get_mock_rodc_krbtgt_creds(self, + require_keys=True, + require_strongest_key=False): + if require_strongest_key: + self.assertTrue(require_keys) + + def create_rodc_krbtgt_account(): + samdb = self.get_samdb() + + rodc_ctx = self.get_mock_rodc_ctx() + + krbtgt_dn = rodc_ctx.new_krbtgt_dn + + res = samdb.search(base=ldb.Dn(samdb, krbtgt_dn), + scope=ldb.SCOPE_BASE, + attrs=['msDS-KeyVersionNumber', + 'msDS-SecondaryKrbTgtNumber']) + dn = res[0].dn + username = str(rodc_ctx.krbtgt_name) + + creds = KerberosCredentials() + creds.set_domain(self.env_get_var('DOMAIN', 'RODC_KRBTGT')) + creds.set_realm(self.env_get_var('REALM', 'RODC_KRBTGT')) + creds.set_username(username) + + kvno = int(res[0]['msDS-KeyVersionNumber'][0]) + krbtgt_number = int(res[0]['msDS-SecondaryKrbTgtNumber'][0]) + + rodc_kvno = krbtgt_number << 16 | kvno + creds.set_kvno(rodc_kvno) + creds.set_dn(dn) + + keys = self.get_keys(samdb, dn) + self.creds_set_keys(creds, keys) + + return creds + + c = self._get_krb5_creds(prefix='MOCK_RODC_KRBTGT', + allow_missing_password=True, + allow_missing_keys=not require_keys, + require_strongest_key=require_strongest_key, + fallback_creds_fn=create_rodc_krbtgt_account) + return c + def get_krbtgt_creds(self, require_keys=True, require_strongest_key=False): -- 2.25.1 From c6f6b2a5872d955fd691d0fea483918425d7cf82 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 13 Sep 2021 21:24:31 +1200 Subject: [PATCH 037/162] tests/krb5: Allow replicating accounts to the created RODC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Douglas Bagnall (cherry picked from commit 35292bd32225b39ad7a03c3aa53027458f0671eb) --- python/samba/tests/krb5/kdc_base_test.py | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 892d3aaf41f..0e138352b06 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -378,6 +378,16 @@ class KDCBaseTest(RawKerberosTest): exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True) + def reveal_account_to_mock_rodc(self, dn): + samdb = self.get_samdb() + rodc_ctx = self.get_mock_rodc_ctx() + + self.get_secrets( + samdb, + dn, + destination_dsa_guid=rodc_ctx.ntds_guid, + source_dsa_invocation_id=misc.GUID(samdb.invocation_id)) + def check_revealed(self, dn, rodc_dn, revealed=True): samdb = self.get_samdb() @@ -555,8 +565,11 @@ class KDCBaseTest(RawKerberosTest): opts_default = { 'allowed_replication': False, + 'allowed_replication_mock': False, 'denied_replication': False, + 'denied_replication_mock': False, 'revealed_to_rodc': False, + 'revealed_to_mock_rodc': False, 'no_auth_data_required': False, 'supported_enctypes': None, 'not_delegated': False, @@ -583,8 +596,11 @@ class KDCBaseTest(RawKerberosTest): def create_account_opts(self, *, machine_account, allowed_replication, + allowed_replication_mock, denied_replication, + denied_replication_mock, revealed_to_rodc, + revealed_to_mock_rodc, no_auth_data_required, supported_enctypes, not_delegated, @@ -682,6 +698,40 @@ class KDCBaseTest(RawKerberosTest): # Deny replicating this account's secrets to the RODC. self.add_to_group(dn, rodc_dn, 'msDS-NeverRevealGroup') + # Handle secret replication to the mock RODC. + + if allowed_replication_mock or revealed_to_mock_rodc: + # Allow replicating this account's secrets if requested, or allow + # it only temporarily if we want to add the account to the mock + # RODC's msDS-RevealedUsers. + rodc_ctx = self.get_mock_rodc_ctx() + mock_rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn) + + allowed_mock_cleanup = self.add_to_group( + dn, mock_rodc_dn, + 'msDS-RevealOnDemandGroup') + + if revealed_to_mock_rodc: + # Request replicating this account's secrets to the mock RODC, + # which updates msDS-RevealedUsers. + self.reveal_account_to_mock_rodc(dn) + + if not allowed_replication_mock: + # If we don't want replicating secrets to be allowed for this + # account, disable it again. + samdb.modify(allowed_mock_cleanup) + + self.check_revealed(dn, + mock_rodc_dn, + revealed=revealed_to_mock_rodc) + + if denied_replication_mock: + # Deny replicating this account's secrets to the mock RODC. + rodc_ctx = self.get_mock_rodc_ctx() + mock_rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn) + + self.add_to_group(dn, mock_rodc_dn, 'msDS-NeverRevealGroup') + return creds def get_client_creds(self, -- 2.25.1 From 8ee93e08f1c8c373fccef67bcf161b11376c050c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 15:42:28 +1200 Subject: [PATCH 038/162] python: Don't leak file handles Signed-off-by: Joseph Sutton Reviewed-by: Noel Power Reviewed-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit cde38d36b98f1d40e7b58cd4c4b4bedfab76c390) --- python/samba/__init__.py | 12 +++++++----- python/samba/ms_schema.py | 6 +++--- python/samba/schema.py | 9 +++++++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/python/samba/__init__.py b/python/samba/__init__.py index d851bf3606c..e87e9c1b371 100644 --- a/python/samba/__init__.py +++ b/python/samba/__init__.py @@ -218,7 +218,8 @@ class Ldb(_Ldb): :param ldif_path: Path to LDIF file. """ - self.add_ldif(open(ldif_path, 'r').read()) + with open(ldif_path, 'r') as ldif_file: + self.add_ldif(ldif_file.read()) def add_ldif(self, ldif, controls=None): """Add data based on a LDIF string. @@ -280,10 +281,11 @@ def read_and_sub_file(file_name, subst_vars): :param file_name: File to be read (typically from setup directory) param subst_vars: Optional variables to subsitute in the file. """ - data = open(file_name, 'r', encoding="utf-8").read() - if subst_vars is not None: - data = substitute_var(data, subst_vars) - check_all_substituted(data) + with open(file_name, 'r', encoding="utf-8") as data_file: + data = data_file.read() + if subst_vars is not None: + data = substitute_var(data, subst_vars) + check_all_substituted(data) return data diff --git a/python/samba/ms_schema.py b/python/samba/ms_schema.py index 4946636cbd4..09dfbdde0f7 100644 --- a/python/samba/ms_schema.py +++ b/python/samba/ms_schema.py @@ -296,9 +296,9 @@ def __parse_schema_file(filename, objectClass): out = [] from io import open - f = open(filename, "r", encoding='latin-1') - for entry in __read_raw_entries(f): - out.append(__write_ldif_one(__transform_entry(entry, objectClass))) + with open(filename, "r", encoding='latin-1') as f: + for entry in __read_raw_entries(f): + out.append(__write_ldif_one(__transform_entry(entry, objectClass))) return "\n\n".join(out) diff --git a/python/samba/schema.py b/python/samba/schema.py index caea7e358ae..083af5f44b0 100644 --- a/python/samba/schema.py +++ b/python/samba/schema.py @@ -110,8 +110,13 @@ class Schema(object): setup_path('ad-schema/%s' % Schema.base_schemas[base_schema][0]), setup_path('ad-schema/%s' % Schema.base_schemas[base_schema][1])) + def read_file(file): + with open(file, 'rb') as data_file: + return data_file.read() + if files is not None: - self.schema_data = "".join(get_string(open(file, 'rb').read()) for file in files) + self.schema_data = "".join(get_string(read_file(file)) + for file in files) self.schema_data = substitute_var(self.schema_data, {"SCHEMADN": schemadn}) @@ -130,7 +135,7 @@ class Schema(object): if override_prefixmap is not None: self.prefixmap_data = override_prefixmap else: - self.prefixmap_data = open(setup_path("prefixMap.txt"), 'rb').read() + self.prefixmap_data = read_file(setup_path("prefixMap.txt")) if additional_prefixmap is not None: self.prefixmap_data += "".join("%s\n" % map for map in additional_prefixmap) -- 2.25.1 From 8412926574b6a1b96aa8f9f5098e5c2e30f8be22 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 10 Sep 2021 14:02:22 +1200 Subject: [PATCH 039/162] python/join: Check for correct msDS-KrbTgtLink attribute Previously, the wrong case was used when checking for this attribute, which meant krbtgt accounts were not being cleaned up. Signed-off-by: Joseph Sutton Reviewed-by: Noel Power Reviewed-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 21a7717359082feaddfdf42788648c3d7574c28e) --- python/samba/join.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/samba/join.py b/python/samba/join.py index a35cf1d9a38..a512e18c226 100644 --- a/python/samba/join.py +++ b/python/samba/join.py @@ -258,8 +258,9 @@ class DCJoinContext(object): ctx.del_noerror(res[0].dn, recursive=True) - if "msDS-Krbtgtlink" in res[0]: - ctx.new_krbtgt_dn = res[0]["msDS-Krbtgtlink"][0] + krbtgt_dn = res[0].get('msDS-KrbTgtLink', idx=0) + if krbtgt_dn is not None: + ctx.new_krbtgt_dn = krbtgt_dn ctx.del_noerror(ctx.new_krbtgt_dn) res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(), @@ -338,7 +339,7 @@ class DCJoinContext(object): attrs=["msDS-krbTgtLink", "userAccountControl", "serverReferenceBL", "rIDSetReferences"]) if len(res) == 0: raise Exception("Could not find domain member account '%s' to promote to a DC, use 'samba-tool domain join' instead'" % ctx.samname) - if "msDS-krbTgtLink" in res[0] or "serverReferenceBL" in res[0] or "rIDSetReferences" in res[0]: + if "msDS-KrbTgtLink" in res[0] or "serverReferenceBL" in res[0] or "rIDSetReferences" in res[0]: raise Exception("Account '%s' appears to be an active DC, use 'samba-tool domain join' if you must re-create this account" % ctx.samname) if (int(res[0]["userAccountControl"][0]) & (samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT | samba.dsdb.UF_SERVER_TRUST_ACCOUNT) == 0): -- 2.25.1 From 5c402a5bee9b888ae158e855e2e304a251587879 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 15 Sep 2021 20:56:28 +1200 Subject: [PATCH 040/162] tests/krb5: Add helper method for modifying PACs This method can remove or replace a PAC in an authorization-data container, while additionally returning the original PAC. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit a281ae09bcf35277c830c4112567c72233fd66b8) --- python/samba/tests/krb5/raw_testcase.py | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index cca38fb9480..b7df1ac0879 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -42,6 +42,8 @@ from samba.tests import TestCaseInTempDir import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1 from samba.tests.krb5.rfc4120_constants import ( + AD_IF_RELEVANT, + AD_WIN2K_PAC, FX_FAST_ARMOR_AP_REQUEST, KDC_ERR_GENERIC, KDC_ERR_PREAUTH_FAILED, @@ -2848,6 +2850,49 @@ class RawKerberosTest(TestCaseInTempDir): ticket_blob) self.assertEqual(expected_checksum, checksum) + def replace_pac(self, auth_data, new_pac, expect_pac=True): + if new_pac is not None: + self.assertElementEqual(new_pac, 'ad-type', AD_WIN2K_PAC) + self.assertElementPresent(new_pac, 'ad-data') + + new_auth_data = [] + + ad_relevant = None + old_pac = None + + for authdata_elem in auth_data: + if authdata_elem['ad-type'] == AD_IF_RELEVANT: + ad_relevant = self.der_decode( + authdata_elem['ad-data'], + asn1Spec=krb5_asn1.AD_IF_RELEVANT()) + + relevant_elems = [] + for relevant_elem in ad_relevant: + if relevant_elem['ad-type'] == AD_WIN2K_PAC: + self.assertIsNone(old_pac, 'Multiple PACs detected') + old_pac = relevant_elem['ad-data'] + + if new_pac is not None: + relevant_elems.append(new_pac) + else: + relevant_elems.append(relevant_elem) + if expect_pac: + self.assertIsNotNone(old_pac, 'Expected PAC') + + ad_relevant = self.der_encode( + relevant_elems, + asn1Spec=krb5_asn1.AD_IF_RELEVANT()) + + authdata_elem = self.AuthorizationData_create(AD_IF_RELEVANT, + ad_relevant) + + new_auth_data.append(authdata_elem) + + if expect_pac: + self.assertIsNotNone(ad_relevant, 'Expected AD-RELEVANT') + + return new_auth_data, old_pac + def get_outer_pa_dict(self, kdc_exchange_dict): return self.get_pa_dict(kdc_exchange_dict['req_padata']) -- 2.25.1 From 8d23815be4dcebfb11acfe748e039c09717316e2 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 11:22:28 +1200 Subject: [PATCH 041/162] tests/krb5: Check correct flags element BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 0061fa2c2a26d990ed2e47441bca8797fc9be356) --- python/samba/tests/krb5/raw_testcase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index b7df1ac0879..632f69794e6 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2193,7 +2193,7 @@ class RawKerberosTest(TestCaseInTempDir): else: self.assertElementMissing(encpart_private, 'key-expiration') - self.assertElementFlags(ticket_private, 'flags', + self.assertElementFlags(encpart_private, 'flags', expected_flags, unexpected_flags) self.assertElementPresent(encpart_private, 'authtime') -- 2.25.1 From b84a6daba10fb74bbdc4fed28390ba3a63f2e782 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 11:13:09 +1200 Subject: [PATCH 042/162] tests/krb5: Refactor tgs_req() to use _generic_kdc_exchange BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 2a4d53dc12aa785f696e53ae3376f67375ce455f) --- python/samba/tests/krb5/kdc_base_test.py | 78 +++++++++++++----------- python/samba/tests/krb5/kdc_tgs_tests.py | 3 +- python/samba/tests/krb5/raw_testcase.py | 1 - source4/selftest/tests.py | 18 ++++-- 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 0e138352b06..6a370d3036e 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -52,7 +52,11 @@ from samba.samdb import SamDB, dsdb_Dn from samba.tests import delete_force import samba.tests.krb5.kcrypto as kcrypto -from samba.tests.krb5.raw_testcase import KerberosCredentials, RawKerberosTest +from samba.tests.krb5.raw_testcase import ( + KerberosCredentials, + KerberosTicketCreds, + RawKerberosTest +) import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1 from samba.tests.krb5.rfc4120_constants import ( AD_IF_RELEVANT, @@ -66,7 +70,6 @@ from samba.tests.krb5.rfc4120_constants import ( KU_AS_REP_ENC_PART, KU_ENC_CHALLENGE_CLIENT, KU_PA_ENC_TIMESTAMP, - KU_TGS_REP_ENC_PART_SUB_KEY, KU_TICKET, NT_PRINCIPAL, NT_SRV_HST, @@ -1063,49 +1066,56 @@ class KDCBaseTest(RawKerberosTest): else: self.assertEqual(rep['error-code'], expected, "rep = {%s}" % rep) - def tgs_req(self, cname, sname, realm, ticket, key, etypes): + def tgs_req(self, cname, sname, realm, ticket, key, etypes, + expected_error_mode=0): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' kdc_options = "0" - till = self.get_KerberosTime(offset=36000) - padata = [] subkey = self.RandomKey(key.etype) (ctime, cusec) = self.get_KerberosTimeWithUsec() - req = self.TGS_REQ_create(padata=padata, - cusec=cusec, - ctime=ctime, - ticket=ticket, - kdc_options=str(kdc_options), - cname=cname, - realm=realm, - sname=sname, - from_time=None, - till_time=till, - renew_time=None, - nonce=0x7ffffffe, - etypes=etypes, - addresses=None, - EncAuthorizationData=None, - EncAuthorizationData_key=None, - additional_tickets=None, - ticket_session_key=key, - authenticator_subkey=subkey) - rep = self.send_recv_transaction(req) - self.assertIsNotNone(rep) + tgt = KerberosTicketCreds(ticket, + key, + crealm=realm, + cname=cname) - msg_type = rep['msg-type'] - enc_part = None - if msg_type == KRB_TGS_REP: - enc_part = subkey.decrypt( - KU_TGS_REP_ENC_PART_SUB_KEY, rep['enc-part']['cipher']) - enc_part = self.der_decode( - enc_part, asn1Spec=krb5_asn1.EncTGSRepPart()) - return (rep, enc_part) + if not expected_error_mode: + check_error_fn = None + check_rep_fn = self.generic_check_kdc_rep + else: + check_error_fn = self.generic_check_kdc_error + check_rep_fn = None + + kdc_exchange_dict = self.tgs_exchange_dict( + expected_crealm=realm, + expected_cname=cname, + expected_srealm=realm, + expected_sname=sname, + expected_error_mode=expected_error_mode, + check_error_fn=check_error_fn, + check_rep_fn=check_rep_fn, + check_kdc_private_fn=self.generic_check_kdc_private, + tgt=tgt, + authenticator_subkey=subkey, + kdc_options=str(kdc_options)) + + rep = self._generic_kdc_exchange(kdc_exchange_dict, + cname=None, + realm=realm, + sname=sname, + etypes=etypes) + + if expected_error_mode: + enc_part = None + else: + ticket_creds = kdc_exchange_dict['rep_ticket_creds'] + enc_part = ticket_creds.encpart_private + + return rep, enc_part # Named tuple to contain values of interest when the PAC is decoded. PacData = namedtuple( diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py index 97f9dd41339..dad9e6b88df 100755 --- a/python/samba/tests/krb5/kdc_tgs_tests.py +++ b/python/samba/tests/krb5/kdc_tgs_tests.py @@ -84,7 +84,8 @@ class KdcTgsTests(KDCBaseTest): name_type=NT_PRINCIPAL, names=["host", samdb.host_dns_name()]) - (rep, enc_part) = self.tgs_req(cname, sname, realm, ticket, key, etype) + (rep, enc_part) = self.tgs_req(cname, sname, realm, ticket, key, etype, + expected_error_mode=KDC_ERR_BADMATCH) self.assertIsNone( enc_part, diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 632f69794e6..7eba62b4022 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2039,7 +2039,6 @@ class RawKerberosTest(TestCaseInTempDir): error_code=0) ticket_private = None - self.assertIsNotNone(ticket_decryption_key) if ticket_decryption_key is not None: self.assertElementEqual(ticket_encpart, 'etype', ticket_decryption_key.etype) diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index d7fedde94a0..423f48b6921 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -800,22 +800,26 @@ planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests") planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ccache", environ={ 'ADMIN_USERNAME': '$USERNAME', - 'ADMIN_PASSWORD': '$PASSWORD' + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0' }) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap", environ={ 'ADMIN_USERNAME': '$USERNAME', - 'ADMIN_PASSWORD': '$PASSWORD' + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0' }) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_rpc", environ={ 'ADMIN_USERNAME': '$USERNAME', - 'ADMIN_PASSWORD': '$PASSWORD' + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0' }) planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb", environ={ 'ADMIN_USERNAME': '$USERNAME', - 'ADMIN_PASSWORD': '$PASSWORD' + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0' }) for env in ["ad_dc", smbv1_disabled_testenv]: @@ -1393,7 +1397,8 @@ planpythontestsuite( "samba.tests.krb5.kdc_tgs_tests", environ={ 'ADMIN_USERNAME': '$USERNAME', - 'ADMIN_PASSWORD': '$PASSWORD' + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0' }) planpythontestsuite( "ad_dc", @@ -1408,7 +1413,8 @@ planpythontestsuite( "samba.tests.krb5.ms_kile_client_principal_lookup_tests", environ={ 'ADMIN_USERNAME': '$USERNAME', - 'ADMIN_PASSWORD': '$PASSWORD' + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0' }) for env in [ -- 2.25.1 From 798f109408745d283c4866af3b66e59793d4c4d2 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 11:16:27 +1200 Subject: [PATCH 043/162] tests/krb5: Allow tgs_req() to send additional padata BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 1f0654b8facf3b9b2288d2569a573ff3a5ca4a82) --- python/samba/tests/krb5/kdc_base_test.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 6a370d3036e..57ef1bceb49 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1067,7 +1067,7 @@ class KDCBaseTest(RawKerberosTest): self.assertEqual(rep['error-code'], expected, "rep = {%s}" % rep) def tgs_req(self, cname, sname, realm, ticket, key, etypes, - expected_error_mode=0): + expected_error_mode=0, padata=None): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' @@ -1090,6 +1090,12 @@ class KDCBaseTest(RawKerberosTest): check_error_fn = self.generic_check_kdc_error check_rep_fn = None + def generate_padata(_kdc_exchange_dict, + _callback_dict, + req_body): + + return padata, req_body + kdc_exchange_dict = self.tgs_exchange_dict( expected_crealm=realm, expected_cname=cname, @@ -1099,6 +1105,7 @@ class KDCBaseTest(RawKerberosTest): check_error_fn=check_error_fn, check_rep_fn=check_rep_fn, check_kdc_private_fn=self.generic_check_kdc_private, + generate_padata_fn=generate_padata if padata is not None else None, tgt=tgt, authenticator_subkey=subkey, kdc_options=str(kdc_options)) -- 2.25.1 From 9660069aaf6e348b09580a041f6e4262fc9e314a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 11:18:12 +1200 Subject: [PATCH 044/162] tests/krb5: Allow tgs_req() to specify different kdc-options BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 1a3426da54463c3e454c1b76c3df4e96882e6aa9) --- python/samba/tests/krb5/kdc_base_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 57ef1bceb49..c448f127c0c 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1067,13 +1067,11 @@ class KDCBaseTest(RawKerberosTest): self.assertEqual(rep['error-code'], expected, "rep = {%s}" % rep) def tgs_req(self, cname, sname, realm, ticket, key, etypes, - expected_error_mode=0, padata=None): + expected_error_mode=0, padata=None, kdc_options=0): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' - kdc_options = "0" - subkey = self.RandomKey(key.etype) (ctime, cusec) = self.get_KerberosTimeWithUsec() -- 2.25.1 From 5b69a82fc2c0f2cd9f23347c62a325707a669fdf Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 11:25:01 +1200 Subject: [PATCH 045/162] tests/krb5: Allow tgs_req() to send requests to the RODC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 6403a09d94ab54f89d6e50601ae6b19ab7e6aae7) --- python/samba/tests/krb5/kdc_base_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index c448f127c0c..5ef08eb32fe 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1067,7 +1067,8 @@ class KDCBaseTest(RawKerberosTest): self.assertEqual(rep['error-code'], expected, "rep = {%s}" % rep) def tgs_req(self, cname, sname, realm, ticket, key, etypes, - expected_error_mode=0, padata=None, kdc_options=0): + expected_error_mode=0, padata=None, kdc_options=0, + to_rodc=False): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' @@ -1106,7 +1107,8 @@ class KDCBaseTest(RawKerberosTest): generate_padata_fn=generate_padata if padata is not None else None, tgt=tgt, authenticator_subkey=subkey, - kdc_options=str(kdc_options)) + kdc_options=str(kdc_options), + to_rodc=to_rodc) rep = self._generic_kdc_exchange(kdc_exchange_dict, cname=None, -- 2.25.1 From 8990895caffb47bf687b91e3f61b43c575cd863f Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 11:52:46 +1200 Subject: [PATCH 046/162] tests/krb5: Allow as_req() to specify different kdc-options BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit a5e62d681d81a422bac7bd89dc27ef2314d77457) --- python/samba/tests/krb5/kdc_base_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 5ef08eb32fe..ae62c9d5fc6 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -913,12 +913,11 @@ class KDCBaseTest(RawKerberosTest): fallback_creds_fn=download_krbtgt_creds) return c - def as_req(self, cname, sname, realm, etypes, padata=None): + def as_req(self, cname, sname, realm, etypes, padata=None, kdc_options=0): '''Send a Kerberos AS_REQ, returns the undecoded response ''' till = self.get_KerberosTime(offset=36000) - kdc_options = 0 req = self.AS_REQ_create(padata=padata, kdc_options=str(kdc_options), -- 2.25.1 From ef63d78c29d064a0d0bfffe7c697bed7265c9461 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 12:06:51 +1200 Subject: [PATCH 047/162] tests/krb5: Use PAC buffer type constants from krb5pac.idl BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 3504e99dc5bcc206ca2964012b7fdca541555416) --- python/samba/tests/krb5/kdc_base_test.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index ae62c9d5fc6..2cebd9ef0cf 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1127,13 +1127,6 @@ class KDCBaseTest(RawKerberosTest): PacData = namedtuple( "PacData", "account_name account_sid logon_name upn domain_name") - PAC_LOGON_INFO = 1 - PAC_CREDENTIAL_INFO = 2 - PAC_SRV_CHECKSUM = 6 - PAC_KDC_CHECKSUM = 7 - PAC_LOGON_NAME = 10 - PAC_CONSTRAINED_DELEGATION = 11 - PAC_UPN_DNS_INFO = 12 def get_pac_data(self, authorization_data): '''Decode the PAC element contained in the authorization-data element @@ -1154,15 +1147,15 @@ class KDCBaseTest(RawKerberosTest): for ad in (x for x in buf if x['ad-type'] == AD_WIN2K_PAC): pb = ndr_unpack(krb5pac.PAC_DATA, ad['ad-data']) for pac in pb.buffers: - if pac.type == self.PAC_LOGON_INFO: + if pac.type == krb5pac.PAC_TYPE_LOGON_INFO: account_name = ( pac.info.info.info3.base.account_name) user_sid = ( str(pac.info.info.info3.base.domain_sid) + "-" + str(pac.info.info.info3.base.rid)) - elif pac.type == self.PAC_LOGON_NAME: + elif pac.type == krb5pac.PAC_TYPE_LOGON_NAME: logon_name = pac.info.account_name - elif pac.type == self.PAC_UPN_DNS_INFO: + elif pac.type == krb5pac.PAC_TYPE_UPN_DNS_INFO: upn = pac.info.upn_name domain_name = pac.info.dns_domain_name -- 2.25.1 From c5b5795c78b235c087de70197dc77e9f29baee54 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 12:13:51 +1200 Subject: [PATCH 048/162] tests/krb5: Don't manually create PAC request and options in fast_tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit c226029655ca361560d93298a6729a021f2f6b75) --- python/samba/tests/krb5/fast_tests.py | 17 +++++++++-------- python/samba/tests/krb5/raw_testcase.py | 5 ----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 8024b92f445..dedf7a57a4b 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1553,10 +1553,7 @@ class FAST_Tests(KDCBaseTest): 'canonicalize,' 'renewable-ok')) - pac_request = self.get_pa_pac_request() - pac_options = self.get_pa_pac_options('1') # supports claims - - padata = [pac_request, pac_options] + pac_options = '1' # supports claims rep, kdc_exchange_dict = self._test_as_exchange( cname=cname, @@ -1571,10 +1568,12 @@ class FAST_Tests(KDCBaseTest): expected_sname=sname, expected_salt=salt, etypes=etype, - padata=padata, + padata=None, kdc_options=kdc_options, preauth_key=None, - ticket_decryption_key=ticket_decryption_key) + ticket_decryption_key=ticket_decryption_key, + pac_request=True, + pac_options=pac_options) self.check_pre_authentication(rep) etype_info2 = kdc_exchange_dict['preauth_etype_info2'] @@ -1585,7 +1584,7 @@ class FAST_Tests(KDCBaseTest): ts_enc_padata = self.get_enc_timestamp_pa_data(creds, rep) - padata = [ts_enc_padata, pac_request, pac_options] + padata = [ts_enc_padata] expected_realm = realm.upper() @@ -1608,7 +1607,9 @@ class FAST_Tests(KDCBaseTest): padata=padata, kdc_options=kdc_options, preauth_key=preauth_key, - ticket_decryption_key=ticket_decryption_key) + ticket_decryption_key=ticket_decryption_key, + pac_request=True, + pac_options=pac_options) self.check_as_reply(rep) tgt = rep['ticket'] diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 7eba62b4022..39821240941 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1177,11 +1177,6 @@ class RawKerberosTest(TestCaseInTempDir): pa_data = self.PA_DATA_create(PADATA_PAC_REQUEST, pa_pac) return pa_data - def get_pa_pac_request(self, request_pac=True): - pac_request = self.KERB_PA_PAC_REQUEST_create(request_pac) - - return pac_request - def get_pa_pac_options(self, options): pac_options = self.PA_PAC_OPTIONS_create(options) pac_options = self.der_encode(pac_options, -- 2.25.1 From ed0073172c10b466f78c6eca637fac6e0b106cf6 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 12:19:28 +1200 Subject: [PATCH 049/162] tests/krb5: Set DN of created accounts to ldb.Dn type BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 7645dfa5bedee7ef3f7debbf0fa7600bd1c4bd79) --- python/samba/tests/krb5/kdc_base_test.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 2cebd9ef0cf..e510ccbe46e 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -228,7 +228,7 @@ class KDCBaseTest(RawKerberosTest): return default_enctypes - def create_account(self, ldb, name, machine_account=False, + def create_account(self, samdb, name, machine_account=False, spn=None, upn=None, additional_details=None, ou=None, account_control=0): '''Create an account for testing. @@ -239,13 +239,13 @@ class KDCBaseTest(RawKerberosTest): guid = (DS_GUID_COMPUTERS_CONTAINER if machine_account else DS_GUID_USERS_CONTAINER) - ou = ldb.get_wellknown_dn(ldb.get_default_basedn(), guid) + ou = samdb.get_wellknown_dn(samdb.get_default_basedn(), guid) dn = "CN=%s,%s" % (name, ou) # remove the account if it exists, this will happen if a previous test # run failed - delete_force(ldb, dn) + delete_force(samdb, dn) if machine_account: object_class = "computer" account_name = "%s$" % name @@ -270,19 +270,19 @@ class KDCBaseTest(RawKerberosTest): details["userPrincipalName"] = upn if additional_details is not None: details.update(additional_details) - ldb.add(details) + samdb.add(details) creds = KerberosCredentials() creds.guess(self.get_lp()) - creds.set_realm(ldb.domain_dns_name().upper()) - creds.set_domain(ldb.domain_netbios_name().upper()) + creds.set_realm(samdb.domain_dns_name().upper()) + creds.set_domain(samdb.domain_netbios_name().upper()) creds.set_password(password) creds.set_username(account_name) if machine_account: creds.set_workstation(name) else: creds.set_workstation('') - creds.set_dn(dn) + creds.set_dn(ldb.Dn(samdb, dn)) # # Save the account name so it can be deleted in tearDownClass self.accounts.add(dn) -- 2.25.1 From 87c03f9d02c70382ebd63c0b78554dbdc593cc5e Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 12:38:38 +1200 Subject: [PATCH 050/162] tests/krb5: Allow get_service_ticket() to get tickets from the RODC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 5d3a135c2326edc9ca8f56bea24d2f52320f4fd6) --- python/samba/tests/krb5/fast_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index dedf7a57a4b..74fe11c5a90 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1497,7 +1497,7 @@ class FAST_Tests(KDCBaseTest): self.assertTrue( security.KERB_ENCTYPE_CLAIMS_SUPPORTED & krbtgt_etypes) - def get_service_ticket(self, tgt, target_creds, service='host'): + def get_service_ticket(self, tgt, target_creds, service='host', to_rodc=False): etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) key = tgt.session_key @@ -1510,7 +1510,7 @@ class FAST_Tests(KDCBaseTest): sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, names=[service, target_name]) - rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype) + rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype, to_rodc=to_rodc) service_ticket = rep['ticket'] -- 2.25.1 From c7830f775c2fa4f8bf57020f698d67486b9c342e Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 12:41:46 +1200 Subject: [PATCH 051/162] tests/krb5: Allow get_tgt() to get tickets from the RODC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 2d69805b1e3a8022f1418605e5f29ae0bbaa4a06) --- python/samba/tests/krb5/fast_tests.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 74fe11c5a90..9109a63d704 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1530,7 +1530,7 @@ class FAST_Tests(KDCBaseTest): return service_ticket_creds - def get_tgt(self, creds): + def get_tgt(self, creds, to_rodc=False): user_name = creds.get_username() realm = creds.get_realm() @@ -1544,7 +1544,10 @@ class FAST_Tests(KDCBaseTest): till = self.get_KerberosTime(offset=36000) - krbtgt_creds = self.get_krbtgt_creds() + if to_rodc: + krbtgt_creds = self.get_rodc_krbtgt_creds() + else: + krbtgt_creds = self.get_krbtgt_creds() ticket_decryption_key = ( self.TicketDecryptionKey_from_creds(krbtgt_creds)) @@ -1573,7 +1576,8 @@ class FAST_Tests(KDCBaseTest): preauth_key=None, ticket_decryption_key=ticket_decryption_key, pac_request=True, - pac_options=pac_options) + pac_options=pac_options, + to_rodc=to_rodc) self.check_pre_authentication(rep) etype_info2 = kdc_exchange_dict['preauth_etype_info2'] @@ -1609,7 +1613,8 @@ class FAST_Tests(KDCBaseTest): preauth_key=preauth_key, ticket_decryption_key=ticket_decryption_key, pac_request=True, - pac_options=pac_options) + pac_options=pac_options, + to_rodc=to_rodc) self.check_as_reply(rep) tgt = rep['ticket'] -- 2.25.1 From b1e9a0d2d881e3b17535da39041352ed2522d238 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 13:14:06 +1200 Subject: [PATCH 052/162] tests/krb5: Allow get_tgt() to specify different kdc-options BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 4ecfa82e71b0dd5b71aa97973033c5c72257a0c3) --- python/samba/tests/krb5/fast_tests.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 9109a63d704..826c3536fb9 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1530,7 +1530,7 @@ class FAST_Tests(KDCBaseTest): return service_ticket_creds - def get_tgt(self, creds, to_rodc=False): + def get_tgt(self, creds, to_rodc=False, kdc_options=None): user_name = creds.get_username() realm = creds.get_realm() @@ -1551,10 +1551,12 @@ class FAST_Tests(KDCBaseTest): ticket_decryption_key = ( self.TicketDecryptionKey_from_creds(krbtgt_creds)) - kdc_options = str(krb5_asn1.KDCOptions('forwardable,' + if kdc_options is None: + kdc_options = krb5_asn1.KDCOptions('forwardable,' 'renewable,' 'canonicalize,' - 'renewable-ok')) + 'renewable-ok') + kdc_options = str(kdc_options) pac_options = '1' # supports claims -- 2.25.1 From adb99fa3f3cb2a5746b92c231a0cc9fd86dcf0e7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 13:14:45 +1200 Subject: [PATCH 053/162] tests/krb5: Allow get_tgt() to specify expected and unexpected flags BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 035a8f198555ad1eedf8e2e6c565fbbbe4fbe7ce) --- python/samba/tests/krb5/fast_tests.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 826c3536fb9..fd96c2b9c1a 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1530,7 +1530,8 @@ class FAST_Tests(KDCBaseTest): return service_ticket_creds - def get_tgt(self, creds, to_rodc=False, kdc_options=None): + def get_tgt(self, creds, to_rodc=False, kdc_options=None, + expected_flags=None, unexpected_flags=None): user_name = creds.get_username() realm = creds.get_realm() @@ -1572,6 +1573,8 @@ class FAST_Tests(KDCBaseTest): expected_srealm=realm, expected_sname=sname, expected_salt=salt, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, etypes=etype, padata=None, kdc_options=kdc_options, -- 2.25.1 From 9a4def4de24fb5e6c6b4daa4c6d8097c3a388884 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 13:24:46 +1200 Subject: [PATCH 054/162] tests/krb5: Move get_tgt() and get_service_ticket() to kdc_base_test BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 59c1043be25b92db75ab5676601cb15426ef37a3) --- python/samba/tests/krb5/fast_tests.py | 141 ---------------------- python/samba/tests/krb5/kdc_base_test.py | 144 +++++++++++++++++++++++ 2 files changed, 144 insertions(+), 141 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index fd96c2b9c1a..a74dc2a3cd0 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1497,147 +1497,6 @@ class FAST_Tests(KDCBaseTest): self.assertTrue( security.KERB_ENCTYPE_CLAIMS_SUPPORTED & krbtgt_etypes) - def get_service_ticket(self, tgt, target_creds, service='host', to_rodc=False): - etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) - - key = tgt.session_key - ticket = tgt.ticket - - cname = tgt.cname - realm = tgt.crealm - - target_name = target_creds.get_username()[:-1] - sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, - names=[service, target_name]) - - rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype, to_rodc=to_rodc) - - service_ticket = rep['ticket'] - - ticket_etype = service_ticket['enc-part']['etype'] - target_key = self.TicketDecryptionKey_from_creds(target_creds, - etype=ticket_etype) - - session_key = self.EncryptionKey_import(enc_part['key']) - - service_ticket_creds = KerberosTicketCreds(service_ticket, - session_key, - crealm=realm, - cname=cname, - srealm=realm, - sname=sname, - decryption_key=target_key) - - return service_ticket_creds - - def get_tgt(self, creds, to_rodc=False, kdc_options=None, - expected_flags=None, unexpected_flags=None): - user_name = creds.get_username() - realm = creds.get_realm() - - salt = creds.get_salt() - - etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) - cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, - names=[user_name]) - sname = self.PrincipalName_create(name_type=NT_SRV_INST, - names=['krbtgt', realm]) - - till = self.get_KerberosTime(offset=36000) - - if to_rodc: - krbtgt_creds = self.get_rodc_krbtgt_creds() - else: - krbtgt_creds = self.get_krbtgt_creds() - ticket_decryption_key = ( - self.TicketDecryptionKey_from_creds(krbtgt_creds)) - - if kdc_options is None: - kdc_options = krb5_asn1.KDCOptions('forwardable,' - 'renewable,' - 'canonicalize,' - 'renewable-ok') - kdc_options = str(kdc_options) - - pac_options = '1' # supports claims - - rep, kdc_exchange_dict = self._test_as_exchange( - cname=cname, - realm=realm, - sname=sname, - till=till, - client_as_etypes=etype, - expected_error_mode=KDC_ERR_PREAUTH_REQUIRED, - expected_crealm=realm, - expected_cname=cname, - expected_srealm=realm, - expected_sname=sname, - expected_salt=salt, - expected_flags=expected_flags, - unexpected_flags=unexpected_flags, - etypes=etype, - padata=None, - kdc_options=kdc_options, - preauth_key=None, - ticket_decryption_key=ticket_decryption_key, - pac_request=True, - pac_options=pac_options, - to_rodc=to_rodc) - self.check_pre_authentication(rep) - - etype_info2 = kdc_exchange_dict['preauth_etype_info2'] - - preauth_key = self.PasswordKey_from_etype_info2(creds, - etype_info2[0], - creds.get_kvno()) - - ts_enc_padata = self.get_enc_timestamp_pa_data(creds, rep) - - padata = [ts_enc_padata] - - expected_realm = realm.upper() - - expected_sname = self.PrincipalName_create( - name_type=NT_SRV_INST, names=['krbtgt', realm.upper()]) - - rep, kdc_exchange_dict = self._test_as_exchange( - cname=cname, - realm=realm, - sname=sname, - till=till, - client_as_etypes=etype, - expected_error_mode=0, - expected_crealm=expected_realm, - expected_cname=cname, - expected_srealm=expected_realm, - expected_sname=expected_sname, - expected_salt=salt, - etypes=etype, - padata=padata, - kdc_options=kdc_options, - preauth_key=preauth_key, - ticket_decryption_key=ticket_decryption_key, - pac_request=True, - pac_options=pac_options, - to_rodc=to_rodc) - self.check_as_reply(rep) - - tgt = rep['ticket'] - - enc_part = self.get_as_rep_enc_data(preauth_key, rep) - session_key = self.EncryptionKey_import(enc_part['key']) - - ticket_creds = KerberosTicketCreds( - tgt, - session_key, - crealm=realm, - cname=cname, - srealm=realm, - sname=sname, - decryption_key=ticket_decryption_key) - - return ticket_creds, enc_part - def get_mach_tgt(self): if self.mach_tgt is None: mach_creds = self.get_mach_creds() diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index e510ccbe46e..fbcc89a9b31 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -73,6 +73,7 @@ from samba.tests.krb5.rfc4120_constants import ( KU_TICKET, NT_PRINCIPAL, NT_SRV_HST, + NT_SRV_INST, PADATA_ENCRYPTED_CHALLENGE, PADATA_ENC_TIMESTAMP, PADATA_ETYPE_INFO2, @@ -1123,6 +1124,149 @@ class KDCBaseTest(RawKerberosTest): return rep, enc_part + def get_service_ticket(self, tgt, target_creds, service='host', + to_rodc=False): + etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) + + key = tgt.session_key + ticket = tgt.ticket + + cname = tgt.cname + realm = tgt.crealm + + target_name = target_creds.get_username()[:-1] + sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=[service, target_name]) + + rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype, + to_rodc=to_rodc) + + service_ticket = rep['ticket'] + + ticket_etype = service_ticket['enc-part']['etype'] + target_key = self.TicketDecryptionKey_from_creds(target_creds, + etype=ticket_etype) + + session_key = self.EncryptionKey_import(enc_part['key']) + + service_ticket_creds = KerberosTicketCreds(service_ticket, + session_key, + crealm=realm, + cname=cname, + srealm=realm, + sname=sname, + decryption_key=target_key) + + return service_ticket_creds + + def get_tgt(self, creds, to_rodc=False, kdc_options=None, + expected_flags=None, unexpected_flags=None): + user_name = creds.get_username() + realm = creds.get_realm() + + salt = creds.get_salt() + + etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) + cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=[user_name]) + sname = self.PrincipalName_create(name_type=NT_SRV_INST, + names=['krbtgt', realm]) + + till = self.get_KerberosTime(offset=36000) + + if to_rodc: + krbtgt_creds = self.get_rodc_krbtgt_creds() + else: + krbtgt_creds = self.get_krbtgt_creds() + ticket_decryption_key = ( + self.TicketDecryptionKey_from_creds(krbtgt_creds)) + + if kdc_options is None: + kdc_options = krb5_asn1.KDCOptions('forwardable,' + 'renewable,' + 'canonicalize,' + 'renewable-ok') + kdc_options = str(kdc_options) + + pac_options = '1' # supports claims + + rep, kdc_exchange_dict = self._test_as_exchange( + cname=cname, + realm=realm, + sname=sname, + till=till, + client_as_etypes=etype, + expected_error_mode=KDC_ERR_PREAUTH_REQUIRED, + expected_crealm=realm, + expected_cname=cname, + expected_srealm=realm, + expected_sname=sname, + expected_salt=salt, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, + etypes=etype, + padata=None, + kdc_options=kdc_options, + preauth_key=None, + ticket_decryption_key=ticket_decryption_key, + pac_request=True, + pac_options=pac_options, + to_rodc=to_rodc) + self.check_pre_authentication(rep) + + etype_info2 = kdc_exchange_dict['preauth_etype_info2'] + + preauth_key = self.PasswordKey_from_etype_info2(creds, + etype_info2[0], + creds.get_kvno()) + + ts_enc_padata = self.get_enc_timestamp_pa_data(creds, rep) + + padata = [ts_enc_padata] + + expected_realm = realm.upper() + + expected_sname = self.PrincipalName_create( + name_type=NT_SRV_INST, names=['krbtgt', realm.upper()]) + + rep, kdc_exchange_dict = self._test_as_exchange( + cname=cname, + realm=realm, + sname=sname, + till=till, + client_as_etypes=etype, + expected_error_mode=0, + expected_crealm=expected_realm, + expected_cname=cname, + expected_srealm=expected_realm, + expected_sname=expected_sname, + expected_salt=salt, + etypes=etype, + padata=padata, + kdc_options=kdc_options, + preauth_key=preauth_key, + ticket_decryption_key=ticket_decryption_key, + pac_request=True, + pac_options=pac_options, + to_rodc=to_rodc) + self.check_as_reply(rep) + + tgt = rep['ticket'] + + enc_part = self.get_as_rep_enc_data(preauth_key, rep) + session_key = self.EncryptionKey_import(enc_part['key']) + + ticket_creds = KerberosTicketCreds( + tgt, + session_key, + crealm=realm, + cname=cname, + srealm=realm, + sname=sname, + decryption_key=ticket_decryption_key) + + return ticket_creds, enc_part + # Named tuple to contain values of interest when the PAC is decoded. PacData = namedtuple( "PacData", -- 2.25.1 From f8c07893d33fe3ec4d4dc6fe777ebf6f6bc7cdd7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 11:51:05 +1200 Subject: [PATCH 055/162] tests/krb5: Return encpart from get_tgt() as part of KerberosTicketCreds The encpart is already contained in ticket_creds, so it no longer needs to be returned as a separate value. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 6193f7433b15579aa32b26a146287923c9d3844d) --- python/samba/tests/krb5/fast_tests.py | 8 ++------ python/samba/tests/krb5/kdc_base_test.py | 16 ++-------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index a74dc2a3cd0..42e75e7513c 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -67,11 +67,9 @@ class FAST_Tests(KDCBaseTest): super().setUpClass() cls.user_tgt = None - cls.user_enc_part = None cls.user_service_ticket = None cls.mach_tgt = None - cls.mach_enc_part = None cls.mach_service_ticket = None def setUp(self): @@ -1500,16 +1498,14 @@ class FAST_Tests(KDCBaseTest): def get_mach_tgt(self): if self.mach_tgt is None: mach_creds = self.get_mach_creds() - type(self).mach_tgt, type(self).mach_enc_part = ( - self.get_tgt(mach_creds)) + type(self).mach_tgt = self.get_tgt(mach_creds) return self.mach_tgt def get_user_tgt(self): if self.user_tgt is None: user_creds = self.get_client_creds() - type(self).user_tgt, type(self).user_enc_part = ( - self.get_tgt(user_creds)) + type(self).user_tgt = self.get_tgt(user_creds) return self.user_tgt diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index fbcc89a9b31..28d34210fce 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1251,21 +1251,9 @@ class KDCBaseTest(RawKerberosTest): to_rodc=to_rodc) self.check_as_reply(rep) - tgt = rep['ticket'] + ticket_creds = kdc_exchange_dict['rep_ticket_creds'] - enc_part = self.get_as_rep_enc_data(preauth_key, rep) - session_key = self.EncryptionKey_import(enc_part['key']) - - ticket_creds = KerberosTicketCreds( - tgt, - session_key, - crealm=realm, - cname=cname, - srealm=realm, - sname=sname, - decryption_key=ticket_decryption_key) - - return ticket_creds, enc_part + return ticket_creds # Named tuple to contain values of interest when the PAC is decoded. PacData = namedtuple( -- 2.25.1 From 0ea7045df10e52e8c8517b708c87ced4f5fa79e0 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 11:51:20 +1200 Subject: [PATCH 056/162] tests/krb5: Cache obtained tickets Now tickets obtained with get_tgt() and get_service_ticket() make use of a cache so they can be reused, unless the 'fresh' parameter is specified as true. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit 419e4061ced466ec7e5e23f815823b540ef4751c) --- python/samba/tests/krb5/kdc_base_test.py | 29 ++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 28d34210fce..59175c7bb2f 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -110,6 +110,7 @@ class KDCBaseTest(RawKerberosTest): cls.accounts = set() cls.account_cache = {} + cls.tkt_cache = {} cls._rodc_ctx = None @@ -1125,7 +1126,17 @@ class KDCBaseTest(RawKerberosTest): return rep, enc_part def get_service_ticket(self, tgt, target_creds, service='host', - to_rodc=False): + to_rodc=False, fresh=False): + user_name = tgt.cname['name-string'][0] + target_name = target_creds.get_username() + cache_key = (user_name, target_name, service, to_rodc) + + if not fresh: + ticket = self.tkt_cache.get(cache_key) + + if ticket is not None: + return ticket + etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) key = tgt.session_key @@ -1157,11 +1168,23 @@ class KDCBaseTest(RawKerberosTest): sname=sname, decryption_key=target_key) + self.tkt_cache[cache_key] = service_ticket_creds + return service_ticket_creds def get_tgt(self, creds, to_rodc=False, kdc_options=None, - expected_flags=None, unexpected_flags=None): + expected_flags=None, unexpected_flags=None, + fresh=False): user_name = creds.get_username() + cache_key = (user_name, to_rodc, kdc_options, + expected_flags, unexpected_flags) + + if not fresh: + tgt = self.tkt_cache.get(cache_key) + + if tgt is not None: + return tgt + realm = creds.get_realm() salt = creds.get_salt() @@ -1253,6 +1276,8 @@ class KDCBaseTest(RawKerberosTest): ticket_creds = kdc_exchange_dict['rep_ticket_creds'] + self.tkt_cache[cache_key] = ticket_creds + return ticket_creds # Named tuple to contain values of interest when the PAC is decoded. -- 2.25.1 From 48c23938fe62ea370fb0f0f6b1c76ac52bbabc9b Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 16:54:57 +1200 Subject: [PATCH 057/162] tests/krb5: Add methods for creating zeroed checksums and verifying checksums Creating a zeroed checksum is needed for signing a PAC. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett (cherry picked from commit a562882b15125902c5d89f094b8c9b1150f5d010) --- python/samba/tests/krb5/raw_testcase.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 39821240941..be49f16b1f7 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -232,12 +232,29 @@ class Krb5EncryptionKey: plaintext = kcrypto.decrypt(self.key, usage, ciphertext) return plaintext + def make_zeroed_checksum(self, ctype=None): + if ctype is None: + ctype = self.ctype + + checksum_len = kcrypto.checksum_len(ctype) + return bytes(checksum_len) + def make_checksum(self, usage, plaintext, ctype=None): if ctype is None: ctype = self.ctype cksum = kcrypto.make_checksum(ctype, self.key, usage, plaintext) return cksum + def verify_checksum(self, usage, plaintext, ctype, cksum): + if self.ctype != ctype: + raise AssertionError(f'{self.ctype} != {ctype}') + + kcrypto.verify_checksum(ctype, + self.key, + usage, + plaintext, + cksum) + def export_obj(self): EncryptionKey_obj = { 'keytype': self.etype, -- 2.25.1 From 65051b32d3e60811356c79e4a278dbe505ff0e45 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 16 Sep 2021 17:20:22 +1200 Subject: [PATCH 058/162] tests/krb5: Add RodcPacEncryptionKey type allowing for RODC PAC signatures Signatures created by an RODC have an RODCIdentifier appended to them identifying the RODC's krbtgt account. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Isaac Boukris Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Sep 21 23:55:39 UTC 2021 on sn-devel-184 (cherry picked from commit ec95b3042bf2649c0600cafb12818c27242b5098) --- python/samba/tests/krb5/raw_testcase.py | 45 +++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index be49f16b1f7..e213b5eef9b 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -263,6 +263,45 @@ class Krb5EncryptionKey: return EncryptionKey_obj +class RodcPacEncryptionKey(Krb5EncryptionKey): + def __init__(self, key, kvno, rodc_id=None): + super().__init__(key, kvno) + + if rodc_id is None: + kvno = self.kvno + if kvno is not None: + kvno >>= 16 + kvno &= (1 << 16) - 1 + + rodc_id = kvno or None + + if rodc_id is not None: + self.rodc_id = rodc_id.to_bytes(2, byteorder='little') + else: + self.rodc_id = b'' + + def make_zeroed_checksum(self, ctype=None): + checksum = super().make_zeroed_checksum(ctype) + return checksum + bytes(len(self.rodc_id)) + + def make_checksum(self, usage, plaintext, ctype=None): + checksum = super().make_checksum(usage, plaintext, ctype) + return checksum + self.rodc_id + + def verify_checksum(self, usage, plaintext, ctype, cksum): + if self.rodc_id: + cksum, cksum_rodc_id = cksum[:-2], cksum[-2:] + + if self.rodc_id != cksum_rodc_id: + raise AssertionError(f'{self.rodc_id.hex()} != ' + f'{cksum_rodc_id.hex()}') + + super().verify_checksum(usage, + plaintext, + ctype, + cksum) + + class KerberosCredentials(Credentials): def __init__(self): super(KerberosCredentials, self).__init__() @@ -325,7 +364,7 @@ class KerberosCredentials(Credentials): etype = int(etype) contents = binascii.a2b_hex(hexkey) key = kcrypto.Key(etype, contents) - self.forced_keys[etype] = Krb5EncryptionKey(key, self.kvno) + self.forced_keys[etype] = RodcPacEncryptionKey(key, self.kvno) def get_forced_key(self, etype): etype = int(etype) @@ -982,13 +1021,13 @@ class RawKerberosTest(TestCaseInTempDir): def SessionKey_create(self, etype, contents, kvno=None): key = kcrypto.Key(etype, contents) - return Krb5EncryptionKey(key, kvno) + return RodcPacEncryptionKey(key, kvno) def PasswordKey_create(self, etype=None, pwd=None, salt=None, kvno=None): self.assertIsNotNone(pwd) self.assertIsNotNone(salt) key = kcrypto.string_to_key(etype, pwd, salt) - return Krb5EncryptionKey(key, kvno) + return RodcPacEncryptionKey(key, kvno) def PasswordKey_from_etype_info2(self, creds, etype_info2, kvno=None): e = etype_info2['etype'] -- 2.25.1 From 69aa2a144d60386d8dd58bd7d11938e44685468c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 17 Sep 2021 14:56:51 +1200 Subject: [PATCH 059/162] tests/krb5: Add method to verify ticket PAC checksums BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 12b5e72a35d632516980f6c051a5d83f913079e7) --- python/samba/tests/krb5/raw_testcase.py | 118 +++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index e213b5eef9b..265789cdb26 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -34,8 +34,9 @@ from pyasn1.codec.native.encoder import encode as pyasn1_native_encode from pyasn1.codec.ber.encoder import BitStringEncoder from samba.credentials import Credentials -from samba.dcerpc import security +from samba.dcerpc import krb5pac, security from samba.gensec import FEATURE_SEAL +from samba.ndr import ndr_pack, ndr_unpack import samba.tests from samba.tests import TestCaseInTempDir @@ -418,6 +419,10 @@ class KerberosTicketCreds: class RawKerberosTest(TestCaseInTempDir): """A raw Kerberos Test case.""" + pac_checksum_types = {krb5pac.PAC_TYPE_SRV_CHECKSUM, + krb5pac.PAC_TYPE_KDC_CHECKSUM, + krb5pac.PAC_TYPE_TICKET_CHECKSUM} + etypes_to_test = ( {"value": -1111, "name": "dummy", }, {"value": kcrypto.Enctype.AES256, "name": "aes128", }, @@ -2900,6 +2905,114 @@ class RawKerberosTest(TestCaseInTempDir): ticket_blob) self.assertEqual(expected_checksum, checksum) + def verify_ticket(self, ticket, krbtgt_key, expect_pac=True): + # Check if the ticket is a TGT. + sname = ticket.ticket['sname'] + is_tgt = sname['name-string'][0] == b'krbtgt' + + # Decrypt the ticket. + + key = ticket.decryption_key + enc_part = ticket.ticket['enc-part'] + + self.assertElementEqual(enc_part, 'etype', key.etype) + self.assertElementKVNO(enc_part, 'kvno', key.kvno) + + enc_part = key.decrypt(KU_TICKET, enc_part['cipher']) + enc_part = self.der_decode( + enc_part, asn1Spec=krb5_asn1.EncTicketPart()) + + # Fetch the authorization data from the ticket. + auth_data = enc_part.get('authorization-data') + if expect_pac: + self.assertIsNotNone(auth_data) + elif auth_data is None: + return + + # Get a copy of the authdata with an empty PAC, and the existing PAC + # (if present). + empty_pac = self.get_empty_pac() + auth_data, pac_data = self.replace_pac(auth_data, + empty_pac, + expect_pac=expect_pac) + if not expect_pac: + return + + # Unpack the PAC as both PAC_DATA and PAC_DATA_RAW types. We use the + # raw type to create a new PAC with zeroed signatures for + # verification. This is because on Windows, the resource_groups field + # is added to PAC_LOGON_INFO after the info3 field has been created, + # which results in a different ordering of pointer values than Samba + # (see commit 0e201ecdc53). Using the raw type avoids changing + # PAC_LOGON_INFO, so verification against Windows can work. We still + # need the PAC_DATA type to retrieve the actual checksums, because the + # signatures in the raw type may contain padding bytes. + pac = ndr_unpack(krb5pac.PAC_DATA, + pac_data) + raw_pac = ndr_unpack(krb5pac.PAC_DATA_RAW, + pac_data) + + checksums = {} + + for pac_buffer, raw_pac_buffer in zip(pac.buffers, raw_pac.buffers): + buffer_type = pac_buffer.type + if buffer_type in self.pac_checksum_types: + self.assertNotIn(buffer_type, checksums, + f'Duplicate checksum type {buffer_type}') + + # Fetch the checksum and the checksum type from the PAC buffer. + checksum = pac_buffer.info.signature + ctype = pac_buffer.info.type + if ctype & 1 << 31: + ctype |= -1 << 31 + + checksums[buffer_type] = checksum, ctype + + if buffer_type != krb5pac.PAC_TYPE_TICKET_CHECKSUM: + # Zero the checksum field so that we can later verify the + # checksums. The ticket checksum field is not zeroed. + + signature = ndr_unpack( + krb5pac.PAC_SIGNATURE_DATA, + raw_pac_buffer.info.remaining) + signature.signature = bytes(len(checksum)) + raw_pac_buffer.info.remaining = ndr_pack( + signature) + + # Re-encode the PAC. + pac_data = ndr_pack(raw_pac) + + # Verify the signatures. + + server_checksum, server_ctype = checksums[ + krb5pac.PAC_TYPE_SRV_CHECKSUM] + Krb5EncryptionKey.verify_checksum(key, + KU_NON_KERB_CKSUM_SALT, + pac_data, + server_ctype, + server_checksum) + + kdc_checksum, kdc_ctype = checksums[ + krb5pac.PAC_TYPE_KDC_CHECKSUM] + krbtgt_key.verify_checksum(KU_NON_KERB_CKSUM_SALT, + server_checksum, + kdc_ctype, + kdc_checksum) + + if is_tgt: + self.assertNotIn(krb5pac.PAC_TYPE_TICKET_CHECKSUM, checksums) + else: + ticket_checksum, ticket_ctype = checksums[ + krb5pac.PAC_TYPE_TICKET_CHECKSUM] + enc_part['authorization-data'] = auth_data + enc_part = self.der_encode(enc_part, + asn1Spec=krb5_asn1.EncTicketPart()) + + krbtgt_key.verify_checksum(KU_NON_KERB_CKSUM_SALT, + enc_part, + ticket_ctype, + ticket_checksum) + def replace_pac(self, auth_data, new_pac, expect_pac=True): if new_pac is not None: self.assertElementEqual(new_pac, 'ad-type', AD_WIN2K_PAC) @@ -2943,6 +3056,9 @@ class RawKerberosTest(TestCaseInTempDir): return new_auth_data, old_pac + def get_empty_pac(self): + return self.AuthorizationData_create(AD_WIN2K_PAC, bytes(1)) + def get_outer_pa_dict(self, kdc_exchange_dict): return self.get_pa_dict(kdc_exchange_dict['req_padata']) -- 2.25.1 From b4a53aa05365791db98a28e5784f2e4e26581293 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 17 Sep 2021 15:26:12 +1200 Subject: [PATCH 060/162] tests/krb5: Add method for modifying a ticket and creating PAC checksums BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 1fcde7cb6ce50e0a08097841e92476f320560664) --- python/samba/tests/krb5/raw_testcase.py | 234 ++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 265789cdb26..4ac7698ffab 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -3013,6 +3013,240 @@ class RawKerberosTest(TestCaseInTempDir): ticket_ctype, ticket_checksum) + def modified_ticket(self, + ticket, *, + new_ticket_key=None, + modify_fn=None, + modify_pac_fn=None, + exclude_pac=False, + update_pac_checksums=True, + checksum_keys=None, + include_checksums=None): + if checksum_keys is None: + # A dict containing a key for each checksum type to be created in + # the PAC. + checksum_keys = {} + + if include_checksums is None: + # A dict containing a value for each checksum type; True if the + # checksum type is to be included in the PAC, False if it is to be + # excluded, or None/not present if the checksum is to be included + # based on its presence in the original PAC. + include_checksums = {} + + # Check that the values passed in by the caller make sense. + + self.assertLessEqual(checksum_keys.keys(), self.pac_checksum_types) + self.assertLessEqual(include_checksums.keys(), self.pac_checksum_types) + + if exclude_pac: + self.assertIsNone(modify_pac_fn) + + update_pac_checksums = False + + if not update_pac_checksums: + self.assertFalse(checksum_keys) + self.assertFalse(include_checksums) + + expect_pac = update_pac_checksums or modify_pac_fn is not None + + key = ticket.decryption_key + + if new_ticket_key is None: + # Use the same key to re-encrypt the ticket. + new_ticket_key = key + + if krb5pac.PAC_TYPE_SRV_CHECKSUM not in checksum_keys: + # If the server signature key is not present, fall back to the key + # used to encrypt the ticket. + checksum_keys[krb5pac.PAC_TYPE_SRV_CHECKSUM] = new_ticket_key + + if krb5pac.PAC_TYPE_TICKET_CHECKSUM not in checksum_keys: + # If the ticket signature key is not present, fall back to the key + # used for the KDC signature. + kdc_checksum_key = checksum_keys.get(krb5pac.PAC_TYPE_KDC_CHECKSUM) + if kdc_checksum_key is not None: + checksum_keys[krb5pac.PAC_TYPE_TICKET_CHECKSUM] = ( + kdc_checksum_key) + + # Decrypt the ticket. + + enc_part = ticket.ticket['enc-part'] + + self.assertElementEqual(enc_part, 'etype', key.etype) + self.assertElementKVNO(enc_part, 'kvno', key.kvno) + + enc_part = key.decrypt(KU_TICKET, enc_part['cipher']) + enc_part = self.der_decode( + enc_part, asn1Spec=krb5_asn1.EncTicketPart()) + + # Modify the ticket here. + if modify_fn is not None: + enc_part = modify_fn(enc_part) + + auth_data = enc_part.get('authorization-data') + if expect_pac: + self.assertIsNotNone(auth_data) + if auth_data is not None: + new_pac = None + if not exclude_pac: + # Get a copy of the authdata with an empty PAC, and the + # existing PAC (if present). + empty_pac = self.get_empty_pac() + empty_pac_auth_data, pac_data = self.replace_pac(auth_data, + empty_pac) + + if expect_pac: + self.assertIsNotNone(pac_data) + if pac_data is not None: + pac = ndr_unpack(krb5pac.PAC_DATA, pac_data) + + # Modify the PAC here. + if modify_pac_fn is not None: + pac = modify_pac_fn(pac) + + if update_pac_checksums: + # Get the enc-part with an empty PAC, which is needed + # to create a ticket signature. + enc_part_to_sign = enc_part.copy() + enc_part_to_sign['authorization-data'] = ( + empty_pac_auth_data) + enc_part_to_sign = self.der_encode( + enc_part_to_sign, + asn1Spec=krb5_asn1.EncTicketPart()) + + self.update_pac_checksums(pac, + checksum_keys, + include_checksums, + enc_part_to_sign) + + # Re-encode the PAC. + pac_data = ndr_pack(pac) + new_pac = self.AuthorizationData_create(AD_WIN2K_PAC, + pac_data) + + # Replace the PAC in the authorization data and re-add it to the + # ticket enc-part. + auth_data, _ = self.replace_pac(auth_data, new_pac) + enc_part['authorization-data'] = auth_data + + # Re-encrypt the ticket enc-part with the new key. + enc_part_new = self.der_encode(enc_part, + asn1Spec=krb5_asn1.EncTicketPart()) + enc_part_new = self.EncryptedData_create(new_ticket_key, + KU_TICKET, + enc_part_new) + + # Create a copy of the ticket with the new enc-part. + new_ticket = ticket.ticket.copy() + new_ticket['enc-part'] = enc_part_new + + new_ticket_creds = KerberosTicketCreds( + new_ticket, + session_key=ticket.session_key, + crealm=ticket.crealm, + cname=ticket.cname, + srealm=ticket.srealm, + sname=ticket.sname, + decryption_key=new_ticket_key, + ticket_private=enc_part, + encpart_private=ticket.encpart_private) + + return new_ticket_creds + + def update_pac_checksums(self, + pac, + checksum_keys, + include_checksums, + enc_part=None): + pac_buffers = pac.buffers + checksum_buffers = {} + + # Find the relevant PAC checksum buffers. + for pac_buffer in pac_buffers: + buffer_type = pac_buffer.type + if buffer_type in self.pac_checksum_types: + self.assertNotIn(buffer_type, checksum_buffers, + f'Duplicate checksum type {buffer_type}') + + checksum_buffers[buffer_type] = pac_buffer + + # Create any additional buffers that were requested but not + # present. Conversely, remove any buffers that were requested to be + # removed. + for buffer_type in self.pac_checksum_types: + if buffer_type in checksum_buffers: + if include_checksums.get(buffer_type) is False: + checksum_buffer = checksum_buffers.pop(buffer_type) + + pac.num_buffers -= 1 + pac_buffers.remove(checksum_buffer) + + elif include_checksums.get(buffer_type) is True: + info = krb5pac.PAC_SIGNATURE_DATA() + + checksum_buffer = krb5pac.PAC_BUFFER() + checksum_buffer.type = buffer_type + checksum_buffer.info = info + + pac_buffers.append(checksum_buffer) + pac.num_buffers += 1 + + checksum_buffers[buffer_type] = checksum_buffer + + # Fill the relevant checksum buffers. + for buffer_type, checksum_buffer in checksum_buffers.items(): + checksum_key = checksum_keys[buffer_type] + ctype = checksum_key.ctype & ((1 << 32) - 1) + + if buffer_type == krb5pac.PAC_TYPE_TICKET_CHECKSUM: + self.assertIsNotNone(enc_part) + + signature = checksum_key.make_checksum( + KU_NON_KERB_CKSUM_SALT, + enc_part) + + elif buffer_type == krb5pac.PAC_TYPE_SRV_CHECKSUM: + signature = Krb5EncryptionKey.make_zeroed_checksum( + checksum_key) + + else: + signature = checksum_key.make_zeroed_checksum() + + checksum_buffer.info.signature = signature + checksum_buffer.info.type = ctype + + # Add the new checksum buffers to the PAC. + pac.buffers = pac_buffers + + # Calculate the server and KDC checksums and insert them into the PAC. + + server_checksum_buffer = checksum_buffers.get( + krb5pac.PAC_TYPE_SRV_CHECKSUM) + if server_checksum_buffer is not None: + server_checksum_key = checksum_keys[krb5pac.PAC_TYPE_SRV_CHECKSUM] + + pac_data = ndr_pack(pac) + server_checksum = Krb5EncryptionKey.make_checksum( + server_checksum_key, + KU_NON_KERB_CKSUM_SALT, + pac_data) + + server_checksum_buffer.info.signature = server_checksum + + kdc_checksum_buffer = checksum_buffers.get( + krb5pac.PAC_TYPE_KDC_CHECKSUM) + if kdc_checksum_buffer is not None: + self.assertIsNotNone(server_checksum_buffer) + + kdc_checksum_key = checksum_keys[krb5pac.PAC_TYPE_KDC_CHECKSUM] + + kdc_checksum = kdc_checksum_key.make_checksum( + KU_NON_KERB_CKSUM_SALT, + server_checksum) + + kdc_checksum_buffer.info.signature = kdc_checksum + def replace_pac(self, auth_data, new_pac, expect_pac=True): if new_pac is not None: self.assertElementEqual(new_pac, 'ad-type', AD_WIN2K_PAC) -- 2.25.1 From 8f426d28cfeb8f2171d73a0d646dd6a454322f8e Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 13:33:16 +1200 Subject: [PATCH 061/162] tests/krb5: Simplify adding authdata to ticket by using modified_ticket() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 4c67a53cdca206a118e82b356db0faf0ddc011ab) --- python/samba/tests/krb5/fast_tests.py | 49 +++++-------------------- python/samba/tests/krb5/raw_testcase.py | 8 ++++ 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 42e75e7513c..d8ccfaee325 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -25,10 +25,7 @@ import collections import ldb from samba.dcerpc import security -from samba.tests.krb5.raw_testcase import ( - KerberosTicketCreds, - Krb5EncryptionKey -) +from samba.tests.krb5.raw_testcase import Krb5EncryptionKey from samba.tests.krb5.kdc_base_test import KDCBaseTest from samba.tests.krb5.rfc4120_constants import ( AD_FX_FAST_ARMOR, @@ -45,7 +42,6 @@ from samba.tests.krb5.rfc4120_constants import ( KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS, KRB_AS_REP, KRB_TGS_REP, - KU_TICKET, NT_PRINCIPAL, NT_SRV_INST, PADATA_FX_COOKIE, @@ -1428,44 +1424,19 @@ class FAST_Tests(KDCBaseTest): def gen_tgt_fast_armor_auth_data(self): user_tgt = self.get_user_tgt() - ticket_decryption_key = user_tgt.decryption_key + auth_data = self.generate_fast_armor_auth_data() + + def modify_fn(enc_part): + enc_part['authorization-data'].append(auth_data) - tgt_encpart = self.getElementValue(user_tgt.ticket, 'enc-part') - self.assertElementEqual(tgt_encpart, 'etype', - ticket_decryption_key.etype) - self.assertElementKVNO(tgt_encpart, 'kvno', - ticket_decryption_key.kvno) - tgt_cipher = self.getElementValue(tgt_encpart, 'cipher') - tgt_decpart = ticket_decryption_key.decrypt(KU_TICKET, tgt_cipher) - tgt_private = self.der_decode(tgt_decpart, - asn1Spec=krb5_asn1.EncTicketPart()) + return enc_part - auth_data = self.generate_fast_armor_auth_data() - tgt_private['authorization-data'].append(auth_data) - - # Re-encrypt the user TGT. - tgt_private_new = self.der_encode( - tgt_private, - asn1Spec=krb5_asn1.EncTicketPart()) - tgt_encpart = self.EncryptedData_create(ticket_decryption_key, - KU_TICKET, - tgt_private_new) - user_ticket = user_tgt.ticket.copy() - user_ticket['enc-part'] = tgt_encpart - - user_tgt = KerberosTicketCreds( - user_ticket, - session_key=user_tgt.session_key, - crealm=user_tgt.crealm, - cname=user_tgt.cname, - srealm=user_tgt.srealm, - sname=user_tgt.sname, - decryption_key=user_tgt.decryption_key, - ticket_private=tgt_private, - encpart_private=user_tgt.encpart_private) + checksum_keys = self.get_krbtgt_checksum_key() # Use our modifed TGT to replace the one in the request. - return user_tgt + return self.modified_ticket(user_tgt, + modify_fn=modify_fn, + checksum_keys=checksum_keys) def create_fast_cookie(self, cookie): self.assertIsNotNone(cookie) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 4ac7698ffab..57013caafb1 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -3290,6 +3290,14 @@ class RawKerberosTest(TestCaseInTempDir): return new_auth_data, old_pac + def get_krbtgt_checksum_key(self): + krbtgt_creds = self.get_krbtgt_creds() + krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + + return { + krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key + } + def get_empty_pac(self): return self.AuthorizationData_create(AD_WIN2K_PAC, bytes(1)) -- 2.25.1 From a80e22b7cbea4e3c99abc33ab331416077cd1003 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 17:01:12 +1200 Subject: [PATCH 062/162] tests/krb5: Make get_default_enctypes() return a set of enctype constants This is often more convenient than a bitfield. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 7cedd383bcc1b5652ea65817b464d6e0485c7b8b) --- python/samba/tests/krb5/kdc_base_test.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 59175c7bb2f..3d2d20cb65b 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -222,11 +222,11 @@ class KDCBaseTest(RawKerberosTest): functional_level = self.get_domain_functional_level(samdb) # RC4 should always be supported - default_enctypes = security.KERB_ENCTYPE_RC4_HMAC_MD5 + default_enctypes = {kcrypto.Enctype.RC4} if functional_level >= DS_DOMAIN_FUNCTION_2008: # AES is only supported at functional level 2008 or higher - default_enctypes |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 - default_enctypes |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 + default_enctypes.add(kcrypto.Enctype.AES256) + default_enctypes.add(kcrypto.Enctype.AES128) return default_enctypes @@ -513,12 +513,7 @@ class KDCBaseTest(RawKerberosTest): default_enctypes = self.get_default_enctypes() - if default_enctypes & security.KERB_ENCTYPE_RC4_HMAC_MD5: - self.assertIn(kcrypto.Enctype.RC4, keys) - if default_enctypes & security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96: - self.assertIn(kcrypto.Enctype.AES256, keys) - if default_enctypes & security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96: - self.assertIn(kcrypto.Enctype.AES128, keys) + self.assertCountEqual(default_enctypes, keys) return keys -- 2.25.1 From 1f19c94165cd424e19ec77cd6ad32eae21f7332c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 21:01:46 +1200 Subject: [PATCH 063/162] tests/krb5: Add methods to convert between enctypes and bitfields These methods are useful for converting a collection of encryption types into msDS-SupportedEncryptionTypes bit flags, and vice versa. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 432eba9e09849e74f4c0f2d7826d45cbd2b7ce42) --- python/samba/tests/krb5/kdc_base_test.py | 6 +-- python/samba/tests/krb5/raw_testcase.py | 51 +++++++++++++++++++----- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 3d2d20cb65b..10ad9e6961f 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -633,10 +633,8 @@ class KDCBaseTest(RawKerberosTest): enctypes = supported_enctypes if fast_support: - fast_bits = (security.KERB_ENCTYPE_FAST_SUPPORTED | - security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED | - security.KERB_ENCTYPE_CLAIMS_SUPPORTED) - enctypes = (enctypes or 0) | fast_bits + enctypes = enctypes or 0 + enctypes |= KerberosCredentials.fast_supported_bits if enctypes is not None: details['msDS-SupportedEncryptionTypes'] = str(enctypes) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 57013caafb1..57579126f8a 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -304,6 +304,11 @@ class RodcPacEncryptionKey(Krb5EncryptionKey): class KerberosCredentials(Credentials): + + fast_supported_bits = (security.KERB_ENCTYPE_FAST_SUPPORTED | + security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED | + security.KERB_ENCTYPE_CLAIMS_SUPPORTED) + def __init__(self): super(KerberosCredentials, self).__init__() all_enc_types = 0 @@ -331,26 +336,52 @@ class KerberosCredentials(Credentials): def set_ap_supported_enctypes(self, value): self.ap_supported_enctypes = int(value) - def _get_krb5_etypes(self, supported_enctypes): + etype_map = collections.OrderedDict([ + (kcrypto.Enctype.AES256, + security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96), + (kcrypto.Enctype.AES128, + security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96), + (kcrypto.Enctype.RC4, + security.KERB_ENCTYPE_RC4_HMAC_MD5), + (kcrypto.Enctype.DES_MD5, + security.KERB_ENCTYPE_DES_CBC_MD5), + (kcrypto.Enctype.DES_CRC, + security.KERB_ENCTYPE_DES_CBC_CRC) + ]) + + @classmethod + def etypes_to_bits(self, etypes): + bits = 0 + for etype in etypes: + bit = self.etype_map[etype] + if bits & bit: + raise ValueError(f'Got duplicate etype: {etype}') + bits |= bit + + return bits + + @classmethod + def bits_to_etypes(self, bits): etypes = () + for etype, bit in self.etype_map.items(): + if bit & bits: + bits &= ~bit + etypes += (etype,) - if supported_enctypes & security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96: - etypes += (kcrypto.Enctype.AES256,) - if supported_enctypes & security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96: - etypes += (kcrypto.Enctype.AES128,) - if supported_enctypes & security.KERB_ENCTYPE_RC4_HMAC_MD5: - etypes += (kcrypto.Enctype.RC4,) + bits &= ~self.fast_supported_bits + if bits != 0: + raise ValueError(f'Unsupported etype bits: {bits}') return etypes def get_as_krb5_etypes(self): - return self._get_krb5_etypes(self.as_supported_enctypes) + return self.bits_to_etypes(self.as_supported_enctypes) def get_tgs_krb5_etypes(self): - return self._get_krb5_etypes(self.tgs_supported_enctypes) + return self.bits_to_etypes(self.tgs_supported_enctypes) def get_ap_krb5_etypes(self): - return self._get_krb5_etypes(self.ap_supported_enctypes) + return self.bits_to_etypes(self.ap_supported_enctypes) def set_kvno(self, kvno): # Sign-extend from 32 bits. -- 2.25.1 From a2614f8fa385f00cf6e8b1edf8cc4983d37d90b6 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 17:10:49 +1200 Subject: [PATCH 064/162] tests/krb5: Get supported enctypes for credentials from database Look up the account's msDS-SupportedEncryptionTypes attribute to get the encryption types that it supports. Move the fallback to RC4 to when the ticket decryption key is obtained. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit b6eaf2cf44fb66d8f302d4cab050827a67de3ea4) --- python/samba/tests/krb5/as_req_tests.py | 4 +- python/samba/tests/krb5/kdc_base_test.py | 52 +++++++++++++++++------- python/samba/tests/krb5/raw_testcase.py | 5 ++- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/python/samba/tests/krb5/as_req_tests.py b/python/samba/tests/krb5/as_req_tests.py index 35f88a0c920..8d9b90fee69 100755 --- a/python/samba/tests/krb5/as_req_tests.py +++ b/python/samba/tests/krb5/as_req_tests.py @@ -60,7 +60,7 @@ class AsReqKerberosTests(KDCBaseTest): initial_kdc_options=None): client_creds = self.get_client_creds() client_account = client_creds.get_username() - client_as_etypes = client_creds.get_as_krb5_etypes() + client_as_etypes = self.get_default_enctypes() krbtgt_creds = self.get_krbtgt_creds(require_keys=False) krbtgt_account = krbtgt_creds.get_username() realm = krbtgt_creds.get_realm() @@ -114,7 +114,7 @@ class AsReqKerberosTests(KDCBaseTest): def test_as_req_enc_timestamp(self): client_creds = self.get_client_creds() client_account = client_creds.get_username() - client_as_etypes = client_creds.get_as_krb5_etypes() + client_as_etypes = self.get_default_enctypes() client_kvno = client_creds.get_kvno() krbtgt_creds = self.get_krbtgt_creds(require_strongest_key=True) krbtgt_account = krbtgt_creds.get_username() diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 10ad9e6961f..cdaeaf9f3e1 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -289,6 +289,8 @@ class KDCBaseTest(RawKerberosTest): # Save the account name so it can be deleted in tearDownClass self.accounts.add(dn) + self.creds_set_enctypes(creds) + return (creds, dn) def create_rodc(self, ctx): @@ -522,13 +524,28 @@ class KDCBaseTest(RawKerberosTest): for enctype, key in keys.items(): creds.set_forced_key(enctype, key) - supported_enctypes = 0 - if kcrypto.Enctype.AES256 in keys: - supported_enctypes |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 - if kcrypto.Enctype.AES128 in keys: - supported_enctypes |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 - if kcrypto.Enctype.RC4 in keys: - supported_enctypes |= security.KERB_ENCTYPE_RC4_HMAC_MD5 + def creds_set_enctypes(self, creds): + samdb = self.get_samdb() + + res = samdb.search(creds.get_dn(), + scope=ldb.SCOPE_BASE, + attrs=['msDS-SupportedEncryptionTypes']) + supported_enctypes = res[0].get('msDS-SupportedEncryptionTypes', idx=0) + + if supported_enctypes is None: + supported_enctypes = 0 + + creds.set_as_supported_enctypes(supported_enctypes) + creds.set_tgs_supported_enctypes(supported_enctypes) + creds.set_ap_supported_enctypes(supported_enctypes) + + def creds_set_default_enctypes(self, creds, fast_support=False): + default_enctypes = self.get_default_enctypes() + supported_enctypes = KerberosCredentials.etypes_to_bits( + default_enctypes) + + if fast_support: + supported_enctypes |= KerberosCredentials.fast_supported_bits creds.set_as_supported_enctypes(supported_enctypes) creds.set_tgs_supported_enctypes(supported_enctypes) @@ -662,14 +679,6 @@ class KDCBaseTest(RawKerberosTest): keys = self.get_keys(samdb, dn) self.creds_set_keys(creds, keys) - if machine_account: - if supported_enctypes is not None: - tgs_enctypes = supported_enctypes - else: - tgs_enctypes = security.KERB_ENCTYPE_RC4_HMAC_MD5 - - creds.set_tgs_supported_enctypes(tgs_enctypes) - # Handle secret replication to the RODC. if allowed_replication or revealed_to_rodc: @@ -814,6 +823,11 @@ class KDCBaseTest(RawKerberosTest): keys = self.get_keys(samdb, krbtgt_dn) self.creds_set_keys(creds, keys) + # The RODC krbtgt account should support the default enctypes, + # although it might not have the msDS-SupportedEncryptionTypes + # attribute. + self.creds_set_default_enctypes(creds) + return creds c = self._get_krb5_creds(prefix='RODC_KRBTGT', @@ -858,6 +872,8 @@ class KDCBaseTest(RawKerberosTest): keys = self.get_keys(samdb, dn) self.creds_set_keys(creds, keys) + self.creds_set_enctypes(creds) + return creds c = self._get_krb5_creds(prefix='MOCK_RODC_KRBTGT', @@ -898,6 +914,12 @@ class KDCBaseTest(RawKerberosTest): keys = self.get_keys(samdb, dn) self.creds_set_keys(creds, keys) + # The krbtgt account should support the default enctypes, although + # it might not (on Samba) have the msDS-SupportedEncryptionTypes + # attribute. + self.creds_set_default_enctypes(creds, + fast_support=self.kdc_fast_support) + return creds c = self._get_krb5_creds(prefix='KRBTGT', diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 57579126f8a..8d7778602f5 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1082,7 +1082,10 @@ class RawKerberosTest(TestCaseInTempDir): if etype is None: etypes = creds.get_tgs_krb5_etypes() - etype = etypes[0] + if etypes: + etype = etypes[0] + else: + etype = kcrypto.Enctype.RC4 forced_key = creds.get_forced_key(etype) if forced_key is not None: -- 2.25.1 From d57ff78f799b321a0ce5aee5dbdf53aa89ad3f0b Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 17:11:28 +1200 Subject: [PATCH 065/162] tests/krb5: Correctly check PA-SUPPORTED-ENCTYPES BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 14cd933a9d6af08deb680c9f688b166138d45ed9) --- python/samba/tests/krb5/fast_tests.py | 4 ++++ python/samba/tests/krb5/kdc_base_test.py | 3 +++ python/samba/tests/krb5/raw_testcase.py | 24 +++++++++++++++--------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index d8ccfaee325..431b48f00d6 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1126,6 +1126,7 @@ class FAST_Tests(KDCBaseTest): name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm]) krbtgt_decryption_key = self.TicketDecryptionKey_from_creds( krbtgt_creds) + krbtgt_etypes = krbtgt_creds.tgs_supported_enctypes target_username = target_creds.get_username()[:-1] target_realm = target_creds.get_realm() @@ -1134,6 +1135,7 @@ class FAST_Tests(KDCBaseTest): name_type=NT_SRV_INST, names=[target_service, target_username]) target_decryption_key = self.TicketDecryptionKey_from_creds( target_creds) + target_etypes = target_creds.tgs_supported_enctypes fast_cookie = None preauth_etype_info2 = None @@ -1322,6 +1324,7 @@ class FAST_Tests(KDCBaseTest): expected_anon=expected_anon, expected_srealm=expected_srealm, expected_sname=expected_sname, + expected_supported_etypes=krbtgt_etypes, expected_flags=expected_flags, unexpected_flags=unexpected_flags, ticket_decryption_key=krbtgt_decryption_key, @@ -1355,6 +1358,7 @@ class FAST_Tests(KDCBaseTest): expected_anon=expected_anon, expected_srealm=expected_srealm, expected_sname=expected_sname, + expected_supported_etypes=target_etypes, expected_flags=expected_flags, unexpected_flags=unexpected_flags, ticket_decryption_key=target_decryption_key, diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index cdaeaf9f3e1..646859e85b3 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1267,6 +1267,8 @@ class KDCBaseTest(RawKerberosTest): expected_sname = self.PrincipalName_create( name_type=NT_SRV_INST, names=['krbtgt', realm.upper()]) + expected_etypes = krbtgt_creds.tgs_supported_enctypes + rep, kdc_exchange_dict = self._test_as_exchange( cname=cname, realm=realm, @@ -1279,6 +1281,7 @@ class KDCBaseTest(RawKerberosTest): expected_srealm=expected_realm, expected_sname=expected_sname, expected_salt=salt, + expected_supported_etypes=expected_etypes, etypes=etype, padata=padata, kdc_options=kdc_options, diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 8d7778602f5..c6bc3e553ad 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1879,6 +1879,7 @@ class RawKerberosTest(TestCaseInTempDir): expected_anon=False, expected_srealm=None, expected_sname=None, + expected_supported_etypes=None, expected_flags=None, unexpected_flags=None, ticket_decryption_key=None, @@ -1923,6 +1924,7 @@ class RawKerberosTest(TestCaseInTempDir): 'expected_anon': expected_anon, 'expected_srealm': expected_srealm, 'expected_sname': expected_sname, + 'expected_supported_etypes': expected_supported_etypes, 'expected_flags': expected_flags, 'unexpected_flags': unexpected_flags, 'ticket_decryption_key': ticket_decryption_key, @@ -1963,6 +1965,7 @@ class RawKerberosTest(TestCaseInTempDir): expected_anon=False, expected_srealm=None, expected_sname=None, + expected_supported_etypes=None, expected_flags=None, unexpected_flags=None, ticket_decryption_key=None, @@ -2006,6 +2009,7 @@ class RawKerberosTest(TestCaseInTempDir): 'expected_anon': expected_anon, 'expected_srealm': expected_srealm, 'expected_sname': expected_sname, + 'expected_supported_etypes': expected_supported_etypes, 'expected_flags': expected_flags, 'unexpected_flags': unexpected_flags, 'ticket_decryption_key': ticket_decryption_key, @@ -2312,19 +2316,19 @@ class RawKerberosTest(TestCaseInTempDir): if canonicalize: self.assertIn(PADATA_SUPPORTED_ETYPES, enc_pa_dict) + expected_supported_etypes = kdc_exchange_dict[ + 'expected_supported_etypes'] + expected_supported_etypes |= ( + security.KERB_ENCTYPE_DES_CBC_CRC | + security.KERB_ENCTYPE_DES_CBC_MD5 | + security.KERB_ENCTYPE_RC4_HMAC_MD5) + (supported_etypes,) = struct.unpack( ' Date: Mon, 20 Sep 2021 13:54:39 +1200 Subject: [PATCH 066/162] tests/krb5: Set key version number for all accounts created with create_account() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 054ec1a8cc4ae42918c7c06ef9c66c8a81242655) --- python/samba/tests/krb5/kdc_base_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 646859e85b3..91034a10e15 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -291,6 +291,12 @@ class KDCBaseTest(RawKerberosTest): self.creds_set_enctypes(creds) + res = samdb.search(base=dn, + scope=ldb.SCOPE_BASE, + attrs=['msDS-KeyVersionNumber']) + kvno = int(res[0]['msDS-KeyVersionNumber'][0]) + creds.set_kvno(kvno) + return (creds, dn) def create_rodc(self, ctx): @@ -670,12 +676,6 @@ class KDCBaseTest(RawKerberosTest): additional_details=details, account_control=user_account_control) - res = samdb.search(base=dn, - scope=ldb.SCOPE_BASE, - attrs=['msDS-KeyVersionNumber']) - kvno = int(res[0]['msDS-KeyVersionNumber'][0]) - creds.set_kvno(kvno) - keys = self.get_keys(samdb, dn) self.creds_set_keys(creds, keys) -- 2.25.1 From 2a995642fed6022e4b1bc031808ffecc49f0a3ce Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 13:59:24 +1200 Subject: [PATCH 067/162] tests/krb5: Allow tgs_req() to check the returned ticket enc-part BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 38b4b334caf1b32f1479db3ada48b2028946f5e6) --- python/samba/tests/krb5/kdc_base_test.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 91034a10e15..914112fdfc7 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1084,7 +1084,7 @@ class KDCBaseTest(RawKerberosTest): def tgs_req(self, cname, sname, realm, ticket, key, etypes, expected_error_mode=0, padata=None, kdc_options=0, - to_rodc=False): + to_rodc=False, service_creds=None): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' @@ -1098,6 +1098,12 @@ class KDCBaseTest(RawKerberosTest): crealm=realm, cname=cname) + if service_creds is not None: + decryption_key = self.TicketDecryptionKey_from_creds( + service_creds) + else: + decryption_key = None + if not expected_error_mode: check_error_fn = None check_rep_fn = self.generic_check_kdc_rep @@ -1120,6 +1126,7 @@ class KDCBaseTest(RawKerberosTest): check_error_fn=check_error_fn, check_rep_fn=check_rep_fn, check_kdc_private_fn=self.generic_check_kdc_private, + ticket_decryption_key=decryption_key, generate_padata_fn=generate_padata if padata is not None else None, tgt=tgt, authenticator_subkey=subkey, -- 2.25.1 From 5b2376d614e25de22710ac57426209495f804a59 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 13:58:09 +1200 Subject: [PATCH 068/162] tests/krb5: Add method to get DC credentials BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 9d01043042f1caac98a23cf4d9aa9a02a31a9239) --- python/samba/tests/krb5/kdc_base_test.py | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 914112fdfc7..5de9907d02b 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -930,6 +930,48 @@ class KDCBaseTest(RawKerberosTest): fallback_creds_fn=download_krbtgt_creds) return c + def get_dc_creds(self, + require_keys=True, + require_strongest_key=False): + if require_strongest_key: + self.assertTrue(require_keys) + + def download_dc_creds(): + samdb = self.get_samdb() + + dc_rid = 1000 + dc_sid = '%s-%d' % (samdb.get_domain_sid(), dc_rid) + + res = samdb.search(base='' % dc_sid, + scope=ldb.SCOPE_BASE, + attrs=['sAMAccountName', + 'msDS-KeyVersionNumber']) + dn = res[0].dn + username = str(res[0]['sAMAccountName']) + + creds = KerberosCredentials() + creds.set_domain(self.env_get_var('DOMAIN', 'DC')) + creds.set_realm(self.env_get_var('REALM', 'DC')) + creds.set_username(username) + + kvno = int(res[0]['msDS-KeyVersionNumber'][0]) + creds.set_kvno(kvno) + creds.set_dn(dn) + + keys = self.get_keys(samdb, dn) + self.creds_set_keys(creds, keys) + + self.creds_set_enctypes(creds) + + return creds + + c = self._get_krb5_creds(prefix='DC', + allow_missing_password=True, + allow_missing_keys=not require_keys, + require_strongest_key=require_strongest_key, + fallback_creds_fn=download_dc_creds) + return c + def as_req(self, cname, sname, realm, etypes, padata=None, kdc_options=0): '''Send a Kerberos AS_REQ, returns the undecoded response ''' -- 2.25.1 From 0533b1f8b3a6765bc71800f713d08ea880717875 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 14:08:16 +1200 Subject: [PATCH 069/162] tests/krb5: Fix checking for presence of authorization data BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit f9284d8517edd9ffd96f0c24166a16366f97de8f) --- python/samba/tests/krb5/kdc_base_test.py | 3 ++- .../ms_kile_client_principal_lookup_tests.py | 6 ++++-- python/samba/tests/krb5/raw_testcase.py | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 5de9907d02b..b4d3739aa11 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1126,7 +1126,7 @@ class KDCBaseTest(RawKerberosTest): def tgs_req(self, cname, sname, realm, ticket, key, etypes, expected_error_mode=0, padata=None, kdc_options=0, - to_rodc=False, service_creds=None): + to_rodc=False, service_creds=None, expect_pac=True): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' @@ -1173,6 +1173,7 @@ class KDCBaseTest(RawKerberosTest): tgt=tgt, authenticator_subkey=subkey, kdc_options=str(kdc_options), + expect_pac=expect_pac, to_rodc=to_rodc) rep = self._generic_kdc_exchange(kdc_exchange_dict, diff --git a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py index 99c842701ea..64ebe15ad70 100755 --- a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py +++ b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py @@ -321,7 +321,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + expect_pac=False) self.check_tgs_reply(rep) # Check the contents of the service ticket @@ -695,7 +696,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + expect_pac=False) self.check_tgs_reply(rep) # Check the contents of the service ticket diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index c6bc3e553ad..b531e33041d 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -944,12 +944,15 @@ class RawKerberosTest(TestCaseInTempDir): v = self.getElementValue(obj, elem) self.assertIsNone(v) - def assertElementPresent(self, obj, elem): + def assertElementPresent(self, obj, elem, expect_empty=False): v = self.getElementValue(obj, elem) self.assertIsNotNone(v) if self.strict_checking: if isinstance(v, collections.abc.Container): - self.assertNotEqual(0, len(v)) + if expect_empty: + self.assertEqual(0, len(v)) + else: + self.assertNotEqual(0, len(v)) def assertElementEqual(self, obj, elem, value): v = self.getElementValue(obj, elem) @@ -1907,6 +1910,7 @@ class RawKerberosTest(TestCaseInTempDir): outer_req=None, pac_request=None, pac_options=None, + expect_pac=True, to_rodc=False): if expected_error_mode == 0: expected_error_mode = () @@ -1952,6 +1956,7 @@ class RawKerberosTest(TestCaseInTempDir): 'outer_req': outer_req, 'pac_request': pac_request, 'pac_options': pac_options, + 'expect_pac': expect_pac, 'to_rodc': to_rodc } if callback_dict is None: @@ -1992,6 +1997,7 @@ class RawKerberosTest(TestCaseInTempDir): outer_req=None, pac_request=None, pac_options=None, + expect_pac=True, to_rodc=False): if expected_error_mode == 0: expected_error_mode = () @@ -2036,6 +2042,7 @@ class RawKerberosTest(TestCaseInTempDir): 'outer_req': outer_req, 'pac_request': pac_request, 'pac_options': pac_options, + 'expect_pac': expect_pac, 'to_rodc': to_rodc } if callback_dict is None: @@ -2236,6 +2243,8 @@ class RawKerberosTest(TestCaseInTempDir): armor_key = kdc_exchange_dict['armor_key'] self.verify_ticket_checksum(ticket, ticket_checksum, armor_key) + expect_pac = kdc_exchange_dict['expect_pac'] + ticket_session_key = None if ticket_private is not None: self.assertElementFlags(ticket_private, 'flags', @@ -2265,7 +2274,8 @@ class RawKerberosTest(TestCaseInTempDir): self.assertElementMissing(ticket_private, 'renew-till') if self.strict_checking: self.assertElementEqual(ticket_private, 'caddr', []) - self.assertElementPresent(ticket_private, 'authorization-data') + self.assertElementPresent(ticket_private, 'authorization-data', + expect_empty=not expect_pac) encpart_session_key = None if encpart_private is not None: -- 2.25.1 From 945d6e9ec20e7eed959b83e89a08e0db38a2db7a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 22 Sep 2021 11:41:45 +1200 Subject: [PATCH 070/162] tests/krb5: Provide ticket enc-part key to tgs_req() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit f2f1f3a1e9269f0e7b93006bba2368a6ffbecc7c) --- python/samba/tests/krb5/kdc_base_test.py | 3 +- python/samba/tests/krb5/kdc_tgs_tests.py | 6 ++-- .../ms_kile_client_principal_lookup_tests.py | 28 ++++++++++++------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index b4d3739aa11..b71ae66bf54 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1215,7 +1215,8 @@ class KDCBaseTest(RawKerberosTest): names=[service, target_name]) rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype, - to_rodc=to_rodc) + to_rodc=to_rodc, + service_creds=target_creds) service_ticket = rep['ticket'] diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py index dad9e6b88df..0904233b01f 100755 --- a/python/samba/tests/krb5/kdc_tgs_tests.py +++ b/python/samba/tests/krb5/kdc_tgs_tests.py @@ -132,7 +132,8 @@ class KdcTgsTests(KDCBaseTest): names=["ldap", samdb.host_dns_name()]) (rep, _) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=self.get_dc_creds()) self.check_tgs_reply(rep) @@ -175,7 +176,8 @@ class KdcTgsTests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the service ticket diff --git a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py index 64ebe15ad70..ce796f63ac2 100755 --- a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py +++ b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py @@ -126,7 +126,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the pac, and the ticket @@ -185,7 +186,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, mc.get_realm(), ticket, key, etype) + cname, sname, mc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the pac, and the ticket @@ -247,7 +249,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the service ticket @@ -322,7 +325,7 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): (rep, enc_part) = self.tgs_req( cname, sname, uc.get_realm(), ticket, key, etype, - expect_pac=False) + service_creds=mc, expect_pac=False) self.check_tgs_reply(rep) # Check the contents of the service ticket @@ -390,7 +393,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the pac, and the ticket @@ -492,7 +496,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the pac, and the ticket @@ -555,7 +560,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the pac, and the ticket @@ -619,7 +625,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the pac, and the ticket @@ -697,7 +704,7 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): (rep, enc_part) = self.tgs_req( cname, sname, uc.get_realm(), ticket, key, etype, - expect_pac=False) + service_creds=mc, expect_pac=False) self.check_tgs_reply(rep) # Check the contents of the service ticket @@ -767,7 +774,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): names=[mc.get_username()]) (rep, enc_part) = self.tgs_req( - cname, sname, uc.get_realm(), ticket, key, etype) + cname, sname, uc.get_realm(), ticket, key, etype, + service_creds=mc) self.check_tgs_reply(rep) # Check the contents of the pac, and the ticket -- 2.25.1 From f9bb0a161157247ef5dfffd2263a4f365429c9f1 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 14:05:58 +1200 Subject: [PATCH 071/162] tests/krb5: Simplify account creation BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 394e8db261b10d130c5e5730989bf68f9bf4f85f) --- .../ms_kile_client_principal_lookup_tests.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py index ce796f63ac2..501bc4892f4 100755 --- a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py +++ b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py @@ -282,15 +282,11 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): samdb = self.get_samdb() user_name = "mskileusr" alt_name = "mskilealtsec" - (uc, dn) = self.create_account(samdb, user_name) + (uc, dn) = self.create_account(samdb, user_name, + account_control=UF_DONT_REQUIRE_PREAUTH) realm = uc.get_realm().lower() alt_sec = "Kerberos:%s@%s" % (alt_name, realm) self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec) - self.modify_attribute( - samdb, - dn, - "userAccountControl", - str(UF_NORMAL_ACCOUNT | UF_DONT_REQUIRE_PREAUTH)) mach_name = "mskilemac" (mc, _) = self.create_account(samdb, mach_name, machine_account=True) @@ -660,15 +656,11 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): samdb = self.get_samdb() user_name = "mskileusr" alt_name = "mskilealtsec" - (uc, dn) = self.create_account(samdb, user_name) + (uc, dn) = self.create_account(samdb, user_name, + account_control=UF_DONT_REQUIRE_PREAUTH) realm = uc.get_realm().lower() alt_sec = "Kerberos:%s@%s" % (alt_name, realm) self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec) - self.modify_attribute( - samdb, - dn, - "userAccountControl", - str(UF_NORMAL_ACCOUNT | UF_DONT_REQUIRE_PREAUTH)) ename = alt_name + "@" + realm mach_name = "mskilemac" -- 2.25.1 From 8a1d041941e65b56a9fed9e8034d7bcd71cb170d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 21 Sep 2021 13:54:47 +1200 Subject: [PATCH 072/162] tests/krb5: Add get_rodc_krbtgt_creds() to RawKerberosTest BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 1458cd9065de34c42bd5ec63feb2f66c25103982) --- python/samba/tests/krb5/raw_testcase.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index b531e33041d..59882e44173 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -750,6 +750,17 @@ class RawKerberosTest(TestCaseInTempDir): c.set_gensec_features(c.get_gensec_features() | FEATURE_SEAL) return c + def get_rodc_krbtgt_creds(self, + require_keys=True, + require_strongest_key=False): + if require_strongest_key: + self.assertTrue(require_keys) + c = self._get_krb5_creds(prefix='RODC_KRBTGT', + allow_missing_password=True, + allow_missing_keys=not require_keys, + require_strongest_key=require_strongest_key) + return c + def get_krbtgt_creds(self, require_keys=True, require_strongest_key=False): -- 2.25.1 From 27ca6f762a518ee03ec5470be355b3673dcb8b3a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 14:10:07 +1200 Subject: [PATCH 073/162] tests/krb5: Verify checksums of tickets obtained from the KDC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ea7b550a500d9e458498d37688b67dafd3d9509d) --- python/samba/tests/krb5/raw_testcase.py | 34 +++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 59882e44173..985792887ca 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2254,6 +2254,13 @@ class RawKerberosTest(TestCaseInTempDir): armor_key = kdc_exchange_dict['armor_key'] self.verify_ticket_checksum(ticket, ticket_checksum, armor_key) + to_rodc = kdc_exchange_dict['to_rodc'] + if to_rodc: + krbtgt_creds = self.get_rodc_krbtgt_creds() + else: + krbtgt_creds = self.get_krbtgt_creds() + krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + expect_pac = kdc_exchange_dict['expect_pac'] ticket_session_key = None @@ -2386,6 +2393,9 @@ class RawKerberosTest(TestCaseInTempDir): ticket_private=ticket_private, encpart_private=encpart_private) + if ticket_decryption_key is not None: + self.verify_ticket(ticket_creds, krbtgt_key, expect_pac=expect_pac) + kdc_exchange_dict['rep_ticket_creds'] = ticket_creds def check_pac_options_claims_support(self, pac_options): @@ -3061,16 +3071,20 @@ class RawKerberosTest(TestCaseInTempDir): if is_tgt: self.assertNotIn(krb5pac.PAC_TYPE_TICKET_CHECKSUM, checksums) else: - ticket_checksum, ticket_ctype = checksums[ - krb5pac.PAC_TYPE_TICKET_CHECKSUM] - enc_part['authorization-data'] = auth_data - enc_part = self.der_encode(enc_part, - asn1Spec=krb5_asn1.EncTicketPart()) - - krbtgt_key.verify_checksum(KU_NON_KERB_CKSUM_SALT, - enc_part, - ticket_ctype, - ticket_checksum) + ticket_checksum, ticket_ctype = checksums.get( + krb5pac.PAC_TYPE_TICKET_CHECKSUM, + (None, None)) + if self.strict_checking: + self.assertIsNotNone(ticket_checksum) + if ticket_checksum is not None: + enc_part['authorization-data'] = auth_data + enc_part = self.der_encode(enc_part, + asn1Spec=krb5_asn1.EncTicketPart()) + + krbtgt_key.verify_checksum(KU_NON_KERB_CKSUM_SALT, + enc_part, + ticket_ctype, + ticket_checksum) def modified_ticket(self, ticket, *, -- 2.25.1 From 0ec6f8a7977e3ed56ba3e03061175cf2c36bd27e Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 15:06:18 +1200 Subject: [PATCH 074/162] tests/krb5: Add method to determine if principal is krbtgt BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit c0b81f0dd54d0d71b5d0f5a870b505e82d0e85b8) --- python/samba/tests/krb5/raw_testcase.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 985792887ca..cadf2b50dc9 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2977,7 +2977,7 @@ class RawKerberosTest(TestCaseInTempDir): def verify_ticket(self, ticket, krbtgt_key, expect_pac=True): # Check if the ticket is a TGT. sname = ticket.ticket['sname'] - is_tgt = sname['name-string'][0] == b'krbtgt' + is_tgt = self.is_tgs(sname) # Decrypt the ticket. @@ -3371,6 +3371,10 @@ class RawKerberosTest(TestCaseInTempDir): krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key } + def is_tgs(self, principal): + name = principal['name-string'][0] + return name in ('krbtgt', b'krbtgt') + def get_empty_pac(self): return self.AuthorizationData_create(AD_WIN2K_PAC, bytes(1)) -- 2.25.1 From 51e7799ab826b38ebfcf298dac898002dff6a49a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 15:10:35 +1200 Subject: [PATCH 075/162] tests/krb5: Add classes for testing invalid checksums BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Thu Sep 23 19:28:44 UTC 2021 on sn-devel-184 (cherry picked from commit 5b331443d0698256ee7fcc040a1ab8137efe925d) --- python/samba/tests/krb5/raw_testcase.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index cadf2b50dc9..579d52b3e92 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -303,6 +303,29 @@ class RodcPacEncryptionKey(Krb5EncryptionKey): cksum) +class ZeroedChecksumKey(Krb5EncryptionKey): + def make_checksum(self, usage, plaintext, ctype=None): + return self.make_zeroed_checksum(ctype) + + +class WrongLengthChecksumKey(Krb5EncryptionKey): + def __init__(self, key, kvno, length): + super().__init__(key, kvno) + + self._length = length + + def make_checksum(self, usage, plaintext, ctype=None): + checksum = super().make_checksum(usage, plaintext, ctype) + + diff = self._length - len(checksum) + if diff > 0: + checksum += bytes(diff) + elif diff < 0: + checksum = checksum[:self._length] + + return checksum + + class KerberosCredentials(Credentials): fast_supported_bits = (security.KERB_ENCTYPE_FAST_SUPPORTED | -- 2.25.1 From 44cb91b37a4b86bd8bd6f6299bdd3e0c0b9bcf81 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:16:24 +1300 Subject: [PATCH 076/162] tests/krb5: Rename method parameter For class methods, the name given to the first parameter is generally 'cls' rather than 'self'. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit d501ddca3b7b9c39c0b3eccf19176e3122cf5b9d) --- python/samba/tests/krb5/raw_testcase.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 579d52b3e92..11c0e308e3d 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -373,10 +373,10 @@ class KerberosCredentials(Credentials): ]) @classmethod - def etypes_to_bits(self, etypes): + def etypes_to_bits(cls, etypes): bits = 0 for etype in etypes: - bit = self.etype_map[etype] + bit = cls.etype_map[etype] if bits & bit: raise ValueError(f'Got duplicate etype: {etype}') bits |= bit @@ -384,14 +384,14 @@ class KerberosCredentials(Credentials): return bits @classmethod - def bits_to_etypes(self, bits): + def bits_to_etypes(cls, bits): etypes = () - for etype, bit in self.etype_map.items(): + for etype, bit in cls.etype_map.items(): if bit & bits: bits &= ~bit etypes += (etype,) - bits &= ~self.fast_supported_bits + bits &= ~cls.fast_supported_bits if bits != 0: raise ValueError(f'Unsupported etype bits: {bits}') -- 2.25.1 From e049a8dc8cc535da4c4de050c7e3a9d4a5606ead Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:16:51 +1300 Subject: [PATCH 077/162] tests/krb5: Remove unused parameter BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 8e4b21590836dab02c1864f6ac12b3879c4bd69c) --- python/samba/tests/krb5/raw_testcase.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 11c0e308e3d..1119c9926d7 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2169,7 +2169,6 @@ class RawKerberosTest(TestCaseInTempDir): self.check_rep_padata(kdc_exchange_dict, callback_dict, - rep, fast_response['padata'], error_code=0) @@ -2509,7 +2508,6 @@ class RawKerberosTest(TestCaseInTempDir): etype_info2 = self.check_rep_padata(kdc_exchange_dict, callback_dict, - rep, rep_padata, error_code) @@ -2520,7 +2518,6 @@ class RawKerberosTest(TestCaseInTempDir): def check_rep_padata(self, kdc_exchange_dict, callback_dict, - rep, rep_padata, error_code): rep_msg_type = kdc_exchange_dict['rep_msg_type'] -- 2.25.1 From ed813475b9dbbe0160266c1aff245c466ff898a5 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:23:17 +1300 Subject: [PATCH 078/162] tests/krb5: Allow for missing msDS-KeyVersionNumber attribute BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ce433ff868d3cdf8e8a6e4995d89d6e036335fb6) --- python/samba/tests/krb5/kdc_base_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index b71ae66bf54..bb92bbd65e5 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -294,8 +294,10 @@ class KDCBaseTest(RawKerberosTest): res = samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=['msDS-KeyVersionNumber']) - kvno = int(res[0]['msDS-KeyVersionNumber'][0]) - creds.set_kvno(kvno) + kvno = res[0].get('msDS-KeyVersionNumber', idx=0) + if kvno is not None: + self.assertEqual(int(kvno), 1) + creds.set_kvno(1) return (creds, dn) -- 2.25.1 From dc33097e4cce158eef762db5070bebdc5e6d0c24 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 30 Sep 2021 10:51:01 +1300 Subject: [PATCH 079/162] tests/krb5: Fix sending PA-PAC-OPTIONS and PA-PAC-REQUEST These padata were not being sent if other FAST padata was not specified. Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 6f1282e8d34073d8499ce919908b39645b017cb8) --- python/samba/tests/krb5/raw_testcase.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 1119c9926d7..ceff1b6220e 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1801,8 +1801,6 @@ class RawKerberosTest(TestCaseInTempDir): fast_padata, req_body = generate_fast_padata_fn(kdc_exchange_dict, callback_dict, req_body) - - fast_padata += additional_padata else: fast_padata = [] @@ -1847,6 +1845,7 @@ class RawKerberosTest(TestCaseInTempDir): KU_FAST_REQ_CHKSUM, checksum_blob) + fast_padata += additional_padata fast = generate_fast_fn(kdc_exchange_dict, callback_dict, inner_req_body, -- 2.25.1 From e76ad0051a20bfc02d800130ce2074fb8f70c658 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 30 Sep 2021 10:54:33 +1300 Subject: [PATCH 080/162] tests/krb5: Fix PA-PAC-OPTIONS checking Make the check work correctly if bits other than the claims bit are specified. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 1fd00135fa4dff4331d86b228ccc01f834476997) --- python/samba/tests/krb5/raw_testcase.py | 44 +++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index ceff1b6220e..0217674ed2d 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2354,10 +2354,10 @@ class RawKerberosTest(TestCaseInTempDir): if self.strict_checking: self.assertElementEqual(encpart_private, 'caddr', []) - sent_claims = self.sent_claims(kdc_exchange_dict) + sent_pac_options = self.get_sent_pac_options(kdc_exchange_dict) if self.strict_checking: - if sent_claims or canonicalize: + if canonicalize or '1' in sent_pac_options: self.assertElementPresent(encpart_private, 'encrypted-pa-data') enc_pa_dict = self.get_pa_dict( @@ -2381,12 +2381,15 @@ class RawKerberosTest(TestCaseInTempDir): else: self.assertNotIn(PADATA_SUPPORTED_ETYPES, enc_pa_dict) - # ClaimsCompIdFASTSupported registry key - if sent_claims: + if '1' in sent_pac_options: self.assertIn(PADATA_PAC_OPTIONS, enc_pa_dict) - self.check_pac_options_claims_support( - enc_pa_dict[PADATA_PAC_OPTIONS]) + pac_options = self.der_decode( + enc_pa_dict[PADATA_PAC_OPTIONS], + asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) + + self.assertElementEqual(pac_options, 'options', + sent_pac_options) else: self.assertNotIn(PADATA_PAC_OPTIONS, enc_pa_dict) else: @@ -2419,11 +2422,6 @@ class RawKerberosTest(TestCaseInTempDir): kdc_exchange_dict['rep_ticket_creds'] = ticket_creds - def check_pac_options_claims_support(self, pac_options): - pac_options = self.der_decode(pac_options, - asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) - self.assertEqual('1', pac_options['options'][0]) # claims bit - def generic_check_kdc_error(self, kdc_exchange_dict, callback_dict, @@ -2565,8 +2563,9 @@ class RawKerberosTest(TestCaseInTempDir): if not sent_fast and error_code != 0: expected_patypes += (PADATA_PW_SALT,) else: - sent_claims = self.sent_claims(kdc_exchange_dict) - if sent_claims and error_code not in (0, KDC_ERR_GENERIC): + sent_pac_options = self.get_sent_pac_options(kdc_exchange_dict) + if ('1' in sent_pac_options + and error_code not in (0, KDC_ERR_GENERIC)): expected_patypes += (PADATA_PAC_OPTIONS,) elif error_code != KDC_ERR_GENERIC: if expect_etype_info: @@ -2656,8 +2655,9 @@ class RawKerberosTest(TestCaseInTempDir): continue if patype == PADATA_PAC_OPTIONS: self.assertIsNone(pac_options) - pac_options = pavalue - self.assertIsNotNone(pac_options) + pac_options = self.der_decode( + pavalue, + asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) continue if patype == PADATA_PW_SALT: self.assertIsNone(pw_salt) @@ -2677,7 +2677,7 @@ class RawKerberosTest(TestCaseInTempDir): inner=True) if pac_options is not None: - self.check_pac_options_claims_support(pac_options) + self.assertElementEqual(pac_options, 'options', sent_pac_options) if pw_salt is not None: self.assertEqual(12, len(pw_salt)) @@ -3418,19 +3418,21 @@ class RawKerberosTest(TestCaseInTempDir): return PADATA_ENCRYPTED_CHALLENGE in fast_pa_dict - def sent_claims(self, kdc_exchange_dict): + def get_sent_pac_options(self, kdc_exchange_dict): fast_pa_dict = self.get_fast_pa_dict(kdc_exchange_dict) if PADATA_PAC_OPTIONS not in fast_pa_dict: - return False + return '' pac_options = self.der_decode(fast_pa_dict[PADATA_PAC_OPTIONS], asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) pac_options = pac_options['options'] - claims_pos = len(tuple(krb5_asn1.PACOptionFlags('claims'))) - 1 - return (claims_pos < len(pac_options) - and pac_options[claims_pos] == '1') + # Mask out unsupported bits. + pac_options, remaining = pac_options[:4], pac_options[4:] + pac_options += '0' * len(remaining) + + return pac_options def get_krbtgt_sname(self): krbtgt_creds = self.get_krbtgt_creds() -- 2.25.1 From 93837b635c1a9ecb7ea0356b712b6566ded96270 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:47:39 +1300 Subject: [PATCH 081/162] tests/krb5: Rename allowed_to_delegate_to parameter for clarity This helps to distinguish resourced-based and non-resource-based constrained delegation. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 31817c383c2014224b1397fde610624663313246) --- python/samba/tests/krb5/kdc_base_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index bb92bbd65e5..e6639270f69 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -598,7 +598,7 @@ class KDCBaseTest(RawKerberosTest): 'no_auth_data_required': False, 'supported_enctypes': None, 'not_delegated': False, - 'allowed_to_delegate_to': None, + 'delegation_to_spn': None, 'trusted_to_auth_for_delegation': False, 'fast_support': False } @@ -629,13 +629,13 @@ class KDCBaseTest(RawKerberosTest): no_auth_data_required, supported_enctypes, not_delegated, - allowed_to_delegate_to, + delegation_to_spn, trusted_to_auth_for_delegation, fast_support): if machine_account: self.assertFalse(not_delegated) else: - self.assertIsNone(allowed_to_delegate_to) + self.assertIsNone(delegation_to_spn) self.assertFalse(trusted_to_auth_for_delegation) samdb = self.get_samdb() @@ -664,8 +664,8 @@ class KDCBaseTest(RawKerberosTest): if enctypes is not None: details['msDS-SupportedEncryptionTypes'] = str(enctypes) - if allowed_to_delegate_to: - details['msDS-AllowedToDelegateTo'] = allowed_to_delegate_to + if delegation_to_spn: + details['msDS-AllowedToDelegateTo'] = delegation_to_spn if machine_account: spn = 'host/' + user_name -- 2.25.1 From 39f312c100768b2904bc8c705e0d3c55347597aa Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:50:36 +1300 Subject: [PATCH 082/162] tests/krb5: Allow created accounts to use resource-based constrained delegation BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit bba8cb8dce19e47a7b813efd9a7527e38856435e) --- python/samba/tests/krb5/kdc_base_test.py | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index e6639270f69..918e04a1dbe 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -301,6 +301,30 @@ class KDCBaseTest(RawKerberosTest): return (creds, dn) + def get_security_descriptor(self, dn): + samdb = self.get_samdb() + + sid = self.get_objectSid(samdb, dn) + + owner_sid = security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS) + + ace = security.ace() + ace.access_mask = security.SEC_ADS_GENERIC_ALL + + ace.trustee = security.dom_sid(sid) + + dacl = security.acl() + dacl.revision = security.SECURITY_ACL_REVISION_ADS + dacl.aces = [ace] + dacl.num_aces = 1 + + security_desc = security.descriptor() + security_desc.type |= security.SEC_DESC_DACL_PRESENT + security_desc.owner_sid = owner_sid + security_desc.dacl = dacl + + return ndr_pack(security_desc) + def create_rodc(self, ctx): ctx.nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn] ctx.full_nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn] @@ -599,6 +623,7 @@ class KDCBaseTest(RawKerberosTest): 'supported_enctypes': None, 'not_delegated': False, 'delegation_to_spn': None, + 'delegation_from_dn': None, 'trusted_to_auth_for_delegation': False, 'fast_support': False } @@ -630,12 +655,14 @@ class KDCBaseTest(RawKerberosTest): supported_enctypes, not_delegated, delegation_to_spn, + delegation_from_dn, trusted_to_auth_for_delegation, fast_support): if machine_account: self.assertFalse(not_delegated) else: self.assertIsNone(delegation_to_spn) + self.assertIsNone(delegation_from_dn) self.assertFalse(trusted_to_auth_for_delegation) samdb = self.get_samdb() @@ -667,6 +694,12 @@ class KDCBaseTest(RawKerberosTest): if delegation_to_spn: details['msDS-AllowedToDelegateTo'] = delegation_to_spn + if delegation_from_dn: + security_descriptor = self.get_security_descriptor( + delegation_from_dn) + details['msDS-AllowedToActOnBehalfOfOtherIdentity'] = ( + security_descriptor) + if machine_account: spn = 'host/' + user_name else: -- 2.25.1 From 86c12bf22b0ce718850ef7bd76d89b20f20458ea Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:52:17 +1300 Subject: [PATCH 083/162] tests/krb5: Add assertion to make failures clearer These failures may occur if tests are not run against an RODC. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit cda50b5c505072989abf84c209e16ff4efe2e628) --- python/samba/tests/krb5/kdc_base_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 918e04a1dbe..25433ba1069 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -590,6 +590,7 @@ class KDCBaseTest(RawKerberosTest): scope=ldb.SCOPE_BASE, attrs=[group_attr]) orig_msg = res[0] + self.assertIn(group_attr, orig_msg) members = list(orig_msg[group_attr]) members.append(account_dn) -- 2.25.1 From 6ef06e0fc508b383e65e4621e885101ad78d55c7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:54:49 +1300 Subject: [PATCH 084/162] tests/krb5: Introduce helper method for creating invalid length checksums BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 9d142dc3a452b0f06efc66f422402ee6e553ee7c) --- python/samba/tests/krb5/raw_testcase.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 0217674ed2d..6107442409f 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -314,17 +314,20 @@ class WrongLengthChecksumKey(Krb5EncryptionKey): self._length = length - def make_checksum(self, usage, plaintext, ctype=None): - checksum = super().make_checksum(usage, plaintext, ctype) - - diff = self._length - len(checksum) + @classmethod + def _adjust_to_length(cls, checksum, length): + diff = length - len(checksum) if diff > 0: checksum += bytes(diff) elif diff < 0: - checksum = checksum[:self._length] + checksum = checksum[:length] return checksum + def make_checksum(self, usage, plaintext, ctype=None): + checksum = super().make_checksum(usage, plaintext, ctype) + return self._adjust_to_length(checksum, self._length) + class KerberosCredentials(Credentials): -- 2.25.1 From 15778005784cd0a1b7419778b78962718f1fb453 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:56:21 +1300 Subject: [PATCH 085/162] tests/krb5: Fix method for creating invalid length zeroed checksum Previously the base class method was being used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ae09219c3a1c6d47817f51baf3784e8986c7478d) --- python/samba/tests/krb5/raw_testcase.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 6107442409f..a3f17e4dc4a 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -324,6 +324,9 @@ class WrongLengthChecksumKey(Krb5EncryptionKey): return checksum + def make_zeroed_checksum(self, ctype=None): + return bytes(self._length) + def make_checksum(self, usage, plaintext, ctype=None): checksum = super().make_checksum(usage, plaintext, ctype) return self._adjust_to_length(checksum, self._length) -- 2.25.1 From a94085f8bb506d04b2b3ae640d4c1e6390bdc3e6 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 11:59:42 +1300 Subject: [PATCH 086/162] tests/krb5: Fix checksum generation and verification The KDC and server checksums may be generated using the same key, but only the KDC checksum should have an RODCIdentifier. To fix this, instead of overriding the existing methods, add additional ones for RODC-specific signatures, so that both types of signatures can be generated or verified. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit a927cecafdd5ad6dc5189fa98cb42684c9c3b033) --- python/samba/tests/krb5/raw_testcase.py | 57 ++++++++++++++----------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index a3f17e4dc4a..aefbdd6d761 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -281,15 +281,15 @@ class RodcPacEncryptionKey(Krb5EncryptionKey): else: self.rodc_id = b'' - def make_zeroed_checksum(self, ctype=None): + def make_rodc_zeroed_checksum(self, ctype=None): checksum = super().make_zeroed_checksum(ctype) return checksum + bytes(len(self.rodc_id)) - def make_checksum(self, usage, plaintext, ctype=None): + def make_rodc_checksum(self, usage, plaintext, ctype=None): checksum = super().make_checksum(usage, plaintext, ctype) return checksum + self.rodc_id - def verify_checksum(self, usage, plaintext, ctype, cksum): + def verify_rodc_checksum(self, usage, plaintext, ctype, cksum): if self.rodc_id: cksum, cksum_rodc_id = cksum[:-2], cksum[-2:] @@ -303,12 +303,15 @@ class RodcPacEncryptionKey(Krb5EncryptionKey): cksum) -class ZeroedChecksumKey(Krb5EncryptionKey): +class ZeroedChecksumKey(RodcPacEncryptionKey): def make_checksum(self, usage, plaintext, ctype=None): return self.make_zeroed_checksum(ctype) + def make_rodc_checksum(self, usage, plaintext, ctype=None): + return self.make_rodc_zeroed_checksum(ctype) -class WrongLengthChecksumKey(Krb5EncryptionKey): + +class WrongLengthChecksumKey(RodcPacEncryptionKey): def __init__(self, key, kvno, length): super().__init__(key, kvno) @@ -331,6 +334,13 @@ class WrongLengthChecksumKey(Krb5EncryptionKey): checksum = super().make_checksum(usage, plaintext, ctype) return self._adjust_to_length(checksum, self._length) + def make_rodc_zeroed_checksum(self, ctype=None): + return bytes(self._length) + + def make_rodc_checksum(self, usage, plaintext, ctype=None): + checksum = super().make_rodc_checksum(usage, plaintext, ctype) + return self._adjust_to_length(checksum, self._length) + class KerberosCredentials(Credentials): @@ -3080,18 +3090,17 @@ class RawKerberosTest(TestCaseInTempDir): server_checksum, server_ctype = checksums[ krb5pac.PAC_TYPE_SRV_CHECKSUM] - Krb5EncryptionKey.verify_checksum(key, - KU_NON_KERB_CKSUM_SALT, - pac_data, - server_ctype, - server_checksum) + key.verify_checksum(KU_NON_KERB_CKSUM_SALT, + pac_data, + server_ctype, + server_checksum) kdc_checksum, kdc_ctype = checksums[ krb5pac.PAC_TYPE_KDC_CHECKSUM] - krbtgt_key.verify_checksum(KU_NON_KERB_CKSUM_SALT, - server_checksum, - kdc_ctype, - kdc_checksum) + krbtgt_key.verify_rodc_checksum(KU_NON_KERB_CKSUM_SALT, + server_checksum, + kdc_ctype, + kdc_checksum) if is_tgt: self.assertNotIn(krb5pac.PAC_TYPE_TICKET_CHECKSUM, checksums) @@ -3106,10 +3115,10 @@ class RawKerberosTest(TestCaseInTempDir): enc_part = self.der_encode(enc_part, asn1Spec=krb5_asn1.EncTicketPart()) - krbtgt_key.verify_checksum(KU_NON_KERB_CKSUM_SALT, - enc_part, - ticket_ctype, - ticket_checksum) + krbtgt_key.verify_rodc_checksum(KU_NON_KERB_CKSUM_SALT, + enc_part, + ticket_ctype, + ticket_checksum) def modified_ticket(self, ticket, *, @@ -3300,16 +3309,15 @@ class RawKerberosTest(TestCaseInTempDir): if buffer_type == krb5pac.PAC_TYPE_TICKET_CHECKSUM: self.assertIsNotNone(enc_part) - signature = checksum_key.make_checksum( + signature = checksum_key.make_rodc_checksum( KU_NON_KERB_CKSUM_SALT, enc_part) elif buffer_type == krb5pac.PAC_TYPE_SRV_CHECKSUM: - signature = Krb5EncryptionKey.make_zeroed_checksum( - checksum_key) + signature = checksum_key.make_zeroed_checksum() else: - signature = checksum_key.make_zeroed_checksum() + signature = checksum_key.make_rodc_zeroed_checksum() checksum_buffer.info.signature = signature checksum_buffer.info.type = ctype @@ -3325,8 +3333,7 @@ class RawKerberosTest(TestCaseInTempDir): server_checksum_key = checksum_keys[krb5pac.PAC_TYPE_SRV_CHECKSUM] pac_data = ndr_pack(pac) - server_checksum = Krb5EncryptionKey.make_checksum( - server_checksum_key, + server_checksum = server_checksum_key.make_checksum( KU_NON_KERB_CKSUM_SALT, pac_data) @@ -3339,7 +3346,7 @@ class RawKerberosTest(TestCaseInTempDir): kdc_checksum_key = checksum_keys[krb5pac.PAC_TYPE_KDC_CHECKSUM] - kdc_checksum = kdc_checksum_key.make_checksum( + kdc_checksum = kdc_checksum_key.make_rodc_checksum( KU_NON_KERB_CKSUM_SALT, server_checksum) -- 2.25.1 From 349f9c13b362304446b98f6e04cfea932f0b4177 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 12:03:33 +1300 Subject: [PATCH 087/162] tests/krb5: Allow excluding the PAC server checksum BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit dcf45a151a198f7165cd332a26db78a5d8e8f8c5) --- python/samba/tests/krb5/raw_testcase.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index aefbdd6d761..4c1aedbca0f 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -3342,7 +3342,10 @@ class RawKerberosTest(TestCaseInTempDir): kdc_checksum_buffer = checksum_buffers.get( krb5pac.PAC_TYPE_KDC_CHECKSUM) if kdc_checksum_buffer is not None: - self.assertIsNotNone(server_checksum_buffer) + if server_checksum_buffer is None: + # There's no server signature to make the checksum over, so + # just make the checksum over an empty bytes object. + server_checksum = bytes() kdc_checksum_key = checksum_keys[krb5pac.PAC_TYPE_KDC_CHECKSUM] -- 2.25.1 From a4cedfe59db888129f8e224faf70fff718c880ff Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 12:06:03 +1300 Subject: [PATCH 088/162] tests/krb5: Fix handling authdata with missing PAC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit a4bc712ee02f32c2d04dfc2d99d58931344e5ceb) --- python/samba/tests/krb5/raw_testcase.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 4c1aedbca0f..b9895e547c4 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -3200,11 +3200,11 @@ class RawKerberosTest(TestCaseInTempDir): # Get a copy of the authdata with an empty PAC, and the # existing PAC (if present). empty_pac = self.get_empty_pac() - empty_pac_auth_data, pac_data = self.replace_pac(auth_data, - empty_pac) + empty_pac_auth_data, pac_data = self.replace_pac( + auth_data, + empty_pac, + expect_pac=expect_pac) - if expect_pac: - self.assertIsNotNone(pac_data) if pac_data is not None: pac = ndr_unpack(krb5pac.PAC_DATA, pac_data) @@ -3234,7 +3234,8 @@ class RawKerberosTest(TestCaseInTempDir): # Replace the PAC in the authorization data and re-add it to the # ticket enc-part. - auth_data, _ = self.replace_pac(auth_data, new_pac) + auth_data, _ = self.replace_pac(auth_data, new_pac, + expect_pac=expect_pac) enc_part['authorization-data'] = auth_data # Re-encrypt the ticket enc-part with the new key. -- 2.25.1 From 27251bc68be942a2995046865a75dfbc7ade398c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 12:16:58 +1300 Subject: [PATCH 089/162] tests/krb5: Fix status code checking The type used to encode the status code is actually KERB-ERROR-DATA, rather than PA-DATA. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 012b6fcd1976c6570e9b92c133d8c21e543e5a4f) --- python/samba/tests/krb5/raw_testcase.py | 89 +++++++++----------- python/samba/tests/krb5/rfc4120_constants.py | 6 ++ 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index b9895e547c4..db7db28cac5 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -49,6 +49,7 @@ from samba.tests.krb5.rfc4120_constants import ( KDC_ERR_GENERIC, KDC_ERR_PREAUTH_FAILED, KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS, + KERB_ERR_TYPE_EXTENDED, KRB_AP_REQ, KRB_AS_REP, KRB_AS_REQ, @@ -85,7 +86,6 @@ from samba.tests.krb5.rfc4120_constants import ( PADATA_PAC_REQUEST, PADATA_PK_AS_REQ, PADATA_PK_AS_REP_19, - PADATA_PW_SALT, PADATA_SUPPORTED_ETYPES ) import samba.tests.krb5.kcrypto as kcrypto @@ -2497,34 +2497,51 @@ class RawKerberosTest(TestCaseInTempDir): self.assertIsNotNone(edata) if edata is not None: if rep_msg_type == KRB_TGS_REP and not sent_fast: - rep_padata = [self.der_decode(edata, - asn1Spec=krb5_asn1.PA_DATA())] + error_data = self.der_decode( + edata, + asn1Spec=krb5_asn1.KERB_ERROR_DATA()) + self.assertEqual(KERB_ERR_TYPE_EXTENDED, + error_data['data-type']) + + extended_error = error_data['data-value'] + + self.assertEqual(12, len(extended_error)) + + status = int.from_bytes(extended_error[:4], 'little') + flags = int.from_bytes(extended_error[8:], 'little') + + expected_status = kdc_exchange_dict['expected_status'] + self.assertEqual(expected_status, status) + + self.assertEqual(3, flags) else: + self.assertIsNone(kdc_exchange_dict['expected_status']) + rep_padata = self.der_decode(edata, asn1Spec=krb5_asn1.METHOD_DATA()) - self.assertGreater(len(rep_padata), 0) + self.assertGreater(len(rep_padata), 0) - if sent_fast: - self.assertEqual(1, len(rep_padata)) - rep_pa_dict = self.get_pa_dict(rep_padata) - self.assertIn(PADATA_FX_FAST, rep_pa_dict) + if sent_fast: + self.assertEqual(1, len(rep_padata)) + rep_pa_dict = self.get_pa_dict(rep_padata) + self.assertIn(PADATA_FX_FAST, rep_pa_dict) - armor_key = kdc_exchange_dict['armor_key'] - self.assertIsNotNone(armor_key) - fast_response = self.check_fx_fast_data( - kdc_exchange_dict, - rep_pa_dict[PADATA_FX_FAST], - armor_key, - expect_strengthen_key=False) + armor_key = kdc_exchange_dict['armor_key'] + self.assertIsNotNone(armor_key) + fast_response = self.check_fx_fast_data( + kdc_exchange_dict, + rep_pa_dict[PADATA_FX_FAST], + armor_key, + expect_strengthen_key=False) - rep_padata = fast_response['padata'] + rep_padata = fast_response['padata'] - etype_info2 = self.check_rep_padata(kdc_exchange_dict, - callback_dict, - rep_padata, - error_code) + etype_info2 = self.check_rep_padata(kdc_exchange_dict, + callback_dict, + rep_padata, + error_code) - kdc_exchange_dict['preauth_etype_info2'] = etype_info2 + kdc_exchange_dict['preauth_etype_info2'] = etype_info2 return rep @@ -2576,13 +2593,10 @@ class RawKerberosTest(TestCaseInTempDir): expected_patypes += (PADATA_FX_COOKIE,) if rep_msg_type == KRB_TGS_REP: - if not sent_fast and error_code != 0: - expected_patypes += (PADATA_PW_SALT,) - else: - sent_pac_options = self.get_sent_pac_options(kdc_exchange_dict) - if ('1' in sent_pac_options - and error_code not in (0, KDC_ERR_GENERIC)): - expected_patypes += (PADATA_PAC_OPTIONS,) + sent_pac_options = self.get_sent_pac_options(kdc_exchange_dict) + if ('1' in sent_pac_options + and error_code not in (0, KDC_ERR_GENERIC)): + expected_patypes += (PADATA_PAC_OPTIONS,) elif error_code != KDC_ERR_GENERIC: if expect_etype_info: self.assertGreater(len(expect_etype_info2), 0) @@ -2621,7 +2635,6 @@ class RawKerberosTest(TestCaseInTempDir): fast_error = None fx_fast = None pac_options = None - pw_salt = None for pa in rep_padata: patype = self.getElementValue(pa, 'padata-type') pavalue = self.getElementValue(pa, 'padata-value') @@ -2675,11 +2688,6 @@ class RawKerberosTest(TestCaseInTempDir): pavalue, asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) continue - if patype == PADATA_PW_SALT: - self.assertIsNone(pw_salt) - pw_salt = pavalue - self.assertIsNotNone(pw_salt) - continue if fast_cookie is not None: kdc_exchange_dict['fast_cookie'] = fast_cookie @@ -2695,19 +2703,6 @@ class RawKerberosTest(TestCaseInTempDir): if pac_options is not None: self.assertElementEqual(pac_options, 'options', sent_pac_options) - if pw_salt is not None: - self.assertEqual(12, len(pw_salt)) - - status = int.from_bytes(pw_salt[:4], 'little') - flags = int.from_bytes(pw_salt[8:], 'little') - - expected_status = kdc_exchange_dict['expected_status'] - self.assertEqual(expected_status, status) - - self.assertEqual(3, flags) - else: - self.assertIsNone(kdc_exchange_dict.get('expected_status')) - if enc_challenge is not None: if not sent_enc_challenge: self.assertEqual(len(enc_challenge), 0) diff --git a/python/samba/tests/krb5/rfc4120_constants.py b/python/samba/tests/krb5/rfc4120_constants.py index ac2bac4d91e..76f2b75d94e 100644 --- a/python/samba/tests/krb5/rfc4120_constants.py +++ b/python/samba/tests/krb5/rfc4120_constants.py @@ -78,6 +78,12 @@ KDC_ERR_SKEW = 37 KDC_ERR_GENERIC = 60 KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS = 93 +# Extended error types +KERB_AP_ERR_TYPE_SKEW_RECOVERY = int( + krb5_asn1.KerbErrorDataTypeValues('kERB-AP-ERR-TYPE-SKEW-RECOVERY')) +KERB_ERR_TYPE_EXTENDED = int( + krb5_asn1.KerbErrorDataTypeValues('kERB-ERR-TYPE-EXTENDED')) + # Name types NT_UNKNOWN = int(krb5_asn1.NameTypeValues('kRB5-NT-UNKNOWN')) NT_PRINCIPAL = int(krb5_asn1.NameTypeValues('kRB5-NT-PRINCIPAL')) -- 2.25.1 From 01a3d358b030bac0151224cf0ec851c17adef123 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 13:01:30 +1300 Subject: [PATCH 090/162] tests/krb5: Make expected_sname checking more explicit BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett [abartlet@samba.org backported from commit 8f6d369d709614e2f5c0684882c62f0476bcafa2 as Samba 4.14 as the test which crashes older MIT KDC versions is omitted] --- python/samba/tests/krb5/fast_tests.py | 39 ++++++++++--------------- python/samba/tests/krb5/raw_testcase.py | 6 +--- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 431b48f00d6..5180eb57563 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -99,11 +99,7 @@ class FAST_Tests(KDCBaseTest): ]) def test_simple_no_sname(self): - krbtgt_creds = self.get_krbtgt_creds() - krbtgt_username = krbtgt_creds.get_username() - krbtgt_realm = krbtgt_creds.get_realm() - expected_sname = self.PrincipalName_create( - name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm]) + expected_sname = self.get_krbtgt_sname() self._run_test_sequence([ { @@ -116,11 +112,7 @@ class FAST_Tests(KDCBaseTest): ]) def test_simple_tgs_no_sname(self): - krbtgt_creds = self.get_krbtgt_creds() - krbtgt_username = krbtgt_creds.get_username() - krbtgt_realm = krbtgt_creds.get_realm() - expected_sname = self.PrincipalName_create( - name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm]) + expected_sname = self.get_krbtgt_sname() self._run_test_sequence([ { @@ -134,11 +126,7 @@ class FAST_Tests(KDCBaseTest): ]) def test_fast_no_sname(self): - krbtgt_creds = self.get_krbtgt_creds() - krbtgt_username = krbtgt_creds.get_username() - krbtgt_realm = krbtgt_creds.get_realm() - expected_sname = self.PrincipalName_create( - name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm]) + expected_sname = self.get_krbtgt_sname() self._run_test_sequence([ { @@ -153,11 +141,7 @@ class FAST_Tests(KDCBaseTest): ]) def test_fast_tgs_no_sname(self): - krbtgt_creds = self.get_krbtgt_creds() - krbtgt_username = krbtgt_creds.get_username() - krbtgt_realm = krbtgt_creds.get_realm() - expected_sname = self.PrincipalName_create( - name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm]) + expected_sname = self.get_krbtgt_sname() self._run_test_sequence([ { @@ -830,6 +814,8 @@ class FAST_Tests(KDCBaseTest): ]) def test_fast_ad_fx_fast_armor(self): + expected_sname = self.get_krbtgt_sname() + # If the authenticator or TGT authentication data contains the # AD-fx-fast-armor authdata type, the KDC must reject the request # (RFC6113 5.4.1.1). @@ -849,7 +835,8 @@ class FAST_Tests(KDCBaseTest): 'use_fast': True, 'gen_authdata_fn': self.generate_fast_armor_auth_data, 'gen_tgt_fn': self.get_user_tgt, - 'fast_armor': None + 'fast_armor': None, + 'expected_sname': expected_sname } ]) @@ -877,6 +864,8 @@ class FAST_Tests(KDCBaseTest): ]) def test_fast_ad_fx_fast_armor_ticket(self): + expected_sname = self.get_krbtgt_sname() + # If the authenticator or TGT authentication data contains the # AD-fx-fast-armor authdata type, the KDC must reject the request # (RFC6113 5.4.2). @@ -896,7 +885,8 @@ class FAST_Tests(KDCBaseTest): 'expected_error_mode': KDC_ERR_GENERIC, 'use_fast': True, 'gen_tgt_fn': self.gen_tgt_fast_armor_auth_data, - 'fast_armor': None + 'fast_armor': None, + 'expected_sname': expected_sname } ]) @@ -956,6 +946,8 @@ class FAST_Tests(KDCBaseTest): ]) def test_fast_tgs_no_subkey(self): + expected_sname = self.get_krbtgt_sname() + # Show that omitting the subkey in the TGS-REQ authenticator fails # (RFC6113 5.4.2). self._run_test_sequence([ @@ -965,7 +957,8 @@ class FAST_Tests(KDCBaseTest): 'use_fast': True, 'gen_tgt_fn': self.get_user_tgt, 'fast_armor': None, - 'include_subkey': False + 'include_subkey': False, + 'expected_sname': expected_sname } ]) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index db7db28cac5..f6aeb00dc8f 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2475,11 +2475,7 @@ class RawKerberosTest(TestCaseInTempDir): else: self.assertElementMissing(rep, 'cname') self.assertElementEqualUTF8(rep, 'realm', expected_srealm) - if sent_fast and error_code == KDC_ERR_GENERIC: - self.assertElementEqualPrincipal(rep, 'sname', - self.get_krbtgt_sname()) - else: - self.assertElementEqualPrincipal(rep, 'sname', expected_sname) + self.assertElementEqualPrincipal(rep, 'sname', expected_sname) self.assertElementMissing(rep, 'e-text') if (error_code == KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS or (rep_msg_type == KRB_TGS_REP -- 2.25.1 From 45bd19b51bcb7df3de3ec3f9fb8b7dd26cbab820 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 13:03:49 +1300 Subject: [PATCH 091/162] tests/krb5: Fix assertElementFlags() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 788b3a29eea62f9f38ca8865c7cb7860bdc94bec) --- python/samba/tests/krb5/fast_tests.py | 4 ++-- python/samba/tests/krb5/raw_testcase.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 5180eb57563..cf9b9d718bb 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -1305,10 +1305,10 @@ class FAST_Tests(KDCBaseTest): expected_flags = kdc_dict.pop('expected_flags', None) if expected_flags is not None: - expected_flags = krb5_asn1.KDCOptions(expected_flags) + expected_flags = krb5_asn1.TicketFlags(expected_flags) unexpected_flags = kdc_dict.pop('unexpected_flags', None) if unexpected_flags is not None: - unexpected_flags = krb5_asn1.KDCOptions(unexpected_flags) + unexpected_flags = krb5_asn1.TicketFlags(unexpected_flags) if rep_type == KRB_AS_REP: kdc_exchange_dict = self.as_exchange_dict( diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index f6aeb00dc8f..a24faf1d060 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1053,14 +1053,14 @@ class RawKerberosTest(TestCaseInTempDir): v = self.getElementValue(obj, elem) self.assertIsNotNone(v) if expected is not None: - self.assertIsInstance(expected, krb5_asn1.KDCOptions) + self.assertIsInstance(expected, krb5_asn1.TicketFlags) for i, flag in enumerate(expected): if flag == 1: self.assertEqual('1', v[i], f"'{expected.namedValues[i]}' " f"expected in {v}") if unexpected is not None: - self.assertIsInstance(unexpected, krb5_asn1.KDCOptions) + self.assertIsInstance(unexpected, krb5_asn1.TicketFlags) for i, flag in enumerate(unexpected): if flag == 1: self.assertEqual('0', v[i], -- 2.25.1 From f3745e6f922ae5d952336917feab8c6e1452bcb5 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 14:02:37 +1300 Subject: [PATCH 092/162] tests/krb5: Remove unneeded parameters from ticket cache key BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 7fba83c6c6309a525742c38e904d3e473db99ef1) --- python/samba/tests/krb5/kdc_base_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 25433ba1069..7ddaa53b541 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1278,8 +1278,7 @@ class KDCBaseTest(RawKerberosTest): expected_flags=None, unexpected_flags=None, fresh=False): user_name = creds.get_username() - cache_key = (user_name, to_rodc, kdc_options, - expected_flags, unexpected_flags) + cache_key = (user_name, to_rodc, kdc_options) if not fresh: tgt = self.tkt_cache.get(cache_key) -- 2.25.1 From 4e3ade7f737231daa051ea72a786478978d16cf9 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 15:48:58 +1300 Subject: [PATCH 093/162] tests/krb5: Fix checking for presence of error data BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ab92dc16d20b0996b8c46714652c15019c795095) --- python/samba/tests/krb5/fast_tests.py | 39 +++++++++++++++++------- python/samba/tests/krb5/kdc_base_test.py | 4 ++- python/samba/tests/krb5/kdc_tgs_tests.py | 3 +- python/samba/tests/krb5/raw_testcase.py | 27 ++++++++-------- 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index cf9b9d718bb..28fe0686335 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -107,7 +107,8 @@ class FAST_Tests(KDCBaseTest): 'expected_error_mode': (KDC_ERR_GENERIC, KDC_ERR_S_PRINCIPAL_UNKNOWN), 'use_fast': False, 'sname': None, - 'expected_sname': expected_sname + 'expected_sname': expected_sname, + 'expect_edata': False } ]) @@ -121,7 +122,8 @@ class FAST_Tests(KDCBaseTest): 'use_fast': False, 'gen_tgt_fn': self.get_user_tgt, 'sname': None, - 'expected_sname': expected_sname + 'expected_sname': expected_sname, + 'expect_edata': False } ]) @@ -172,6 +174,7 @@ class FAST_Tests(KDCBaseTest): 'expected_error_mode': KDC_ERR_NOT_US, 'use_fast': False, 'gen_tgt_fn': self.get_user_service_ticket, + 'expect_edata': False } ]) @@ -182,6 +185,7 @@ class FAST_Tests(KDCBaseTest): 'expected_error_mode': KDC_ERR_NOT_US, 'use_fast': False, 'gen_tgt_fn': self.get_mach_service_ticket, + 'expect_edata': False } ]) @@ -294,7 +298,8 @@ class FAST_Tests(KDCBaseTest): 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP, 'use_fast': False, 'gen_tgt_fn': self.get_mach_tgt, - 'etypes': () + 'etypes': (), + 'expect_edata': False } ]) @@ -342,7 +347,8 @@ class FAST_Tests(KDCBaseTest): 'use_fast': True, 'gen_fast_fn': self.generate_empty_fast, 'fast_armor': None, - 'gen_armor_tgt_fn': self.get_mach_tgt + 'gen_armor_tgt_fn': self.get_mach_tgt, + 'expect_edata': False } ]) @@ -365,7 +371,8 @@ class FAST_Tests(KDCBaseTest): 'expected_error_mode': KDC_ERR_GENERIC, 'use_fast': True, 'fast_armor': None, # no armor, - 'gen_armor_tgt_fn': self.get_mach_tgt + 'gen_armor_tgt_fn': self.get_mach_tgt, + 'expect_edata': False } ]) @@ -809,7 +816,8 @@ class FAST_Tests(KDCBaseTest): # should be KRB_APP_ERR_MODIFIED 'use_fast': False, 'gen_authdata_fn': self.generate_fast_used_auth_data, - 'gen_tgt_fn': self.get_user_tgt + 'gen_tgt_fn': self.get_user_tgt, + 'expect_edata': False } ]) @@ -836,7 +844,8 @@ class FAST_Tests(KDCBaseTest): 'gen_authdata_fn': self.generate_fast_armor_auth_data, 'gen_tgt_fn': self.get_user_tgt, 'fast_armor': None, - 'expected_sname': expected_sname + 'expected_sname': expected_sname, + 'expect_edata': False } ]) @@ -886,7 +895,8 @@ class FAST_Tests(KDCBaseTest): 'use_fast': True, 'gen_tgt_fn': self.gen_tgt_fast_armor_auth_data, 'fast_armor': None, - 'expected_sname': expected_sname + 'expected_sname': expected_sname, + 'expect_edata': False } ]) @@ -958,7 +968,8 @@ class FAST_Tests(KDCBaseTest): 'gen_tgt_fn': self.get_user_tgt, 'fast_armor': None, 'include_subkey': False, - 'expected_sname': expected_sname + 'expected_sname': expected_sname, + 'expect_edata': False } ]) @@ -1209,6 +1220,10 @@ class FAST_Tests(KDCBaseTest): else: tgt_cname = client_cname + expect_edata = kdc_dict.pop('expect_edata', None) + if expect_edata is not None: + self.assertTrue(expected_error_mode) + expected_cname = kdc_dict.pop('expected_cname', tgt_cname) expected_anon = kdc_dict.pop('expected_anon', False) @@ -1343,7 +1358,8 @@ class FAST_Tests(KDCBaseTest): inner_req=inner_req, outer_req=outer_req, pac_request=True, - pac_options=pac_options) + pac_options=pac_options, + expect_edata=expect_edata) else: # KRB_TGS_REP kdc_exchange_dict = self.tgs_exchange_dict( expected_crealm=expected_crealm, @@ -1376,7 +1392,8 @@ class FAST_Tests(KDCBaseTest): inner_req=inner_req, outer_req=outer_req, pac_request=None, - pac_options=pac_options) + pac_options=pac_options, + expect_edata=expect_edata) repeat = kdc_dict.pop('repeat', 1) for _ in range(repeat): diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 7ddaa53b541..d25fc0b42b2 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1162,7 +1162,8 @@ class KDCBaseTest(RawKerberosTest): def tgs_req(self, cname, sname, realm, ticket, key, etypes, expected_error_mode=0, padata=None, kdc_options=0, - to_rodc=False, service_creds=None, expect_pac=True): + to_rodc=False, service_creds=None, expect_pac=True, + expect_edata=None): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' @@ -1209,6 +1210,7 @@ class KDCBaseTest(RawKerberosTest): tgt=tgt, authenticator_subkey=subkey, kdc_options=str(kdc_options), + expect_edata=expect_edata, expect_pac=expect_pac, to_rodc=to_rodc) diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py index 0904233b01f..2b55ba8a376 100755 --- a/python/samba/tests/krb5/kdc_tgs_tests.py +++ b/python/samba/tests/krb5/kdc_tgs_tests.py @@ -85,7 +85,8 @@ class KdcTgsTests(KDCBaseTest): names=["host", samdb.host_dns_name()]) (rep, enc_part) = self.tgs_req(cname, sname, realm, ticket, key, etype, - expected_error_mode=KDC_ERR_BADMATCH) + expected_error_mode=KDC_ERR_BADMATCH, + expect_edata=False) self.assertIsNone( enc_part, diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index a24faf1d060..1a3aedbd436 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1959,6 +1959,7 @@ class RawKerberosTest(TestCaseInTempDir): outer_req=None, pac_request=None, pac_options=None, + expect_edata=None, expect_pac=True, to_rodc=False): if expected_error_mode == 0: @@ -2005,6 +2006,7 @@ class RawKerberosTest(TestCaseInTempDir): 'outer_req': outer_req, 'pac_request': pac_request, 'pac_options': pac_options, + 'expect_edata': expect_edata, 'expect_pac': expect_pac, 'to_rodc': to_rodc } @@ -2046,6 +2048,7 @@ class RawKerberosTest(TestCaseInTempDir): outer_req=None, pac_request=None, pac_options=None, + expect_edata=None, expect_pac=True, to_rodc=False): if expected_error_mode == 0: @@ -2091,6 +2094,7 @@ class RawKerberosTest(TestCaseInTempDir): 'outer_req': outer_req, 'pac_request': pac_request, 'pac_options': pac_options, + 'expect_edata': expect_edata, 'expect_pac': expect_pac, 'to_rodc': to_rodc } @@ -2477,20 +2481,20 @@ class RawKerberosTest(TestCaseInTempDir): self.assertElementEqualUTF8(rep, 'realm', expected_srealm) self.assertElementEqualPrincipal(rep, 'sname', expected_sname) self.assertElementMissing(rep, 'e-text') - if (error_code == KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS - or (rep_msg_type == KRB_TGS_REP - and not sent_fast) - or (sent_fast and fast_armor_type is not None - and fast_armor_type != FX_FAST_ARMOR_AP_REQUEST) - or inner): + expected_status = kdc_exchange_dict['expected_status'] + expect_edata = kdc_exchange_dict['expect_edata'] + if expect_edata is None: + expect_edata = (error_code != KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS + and (not sent_fast or fast_armor_type is None + or fast_armor_type == FX_FAST_ARMOR_AP_REQUEST) + and not inner) + if not expect_edata: + self.assertIsNone(expected_status) self.assertElementMissing(rep, 'e-data') return rep edata = self.getElementValue(rep, 'e-data') if self.strict_checking: - if error_code != KDC_ERR_GENERIC: - # Predicting whether an ERR_GENERIC error contains e-data is - # more complicated. - self.assertIsNotNone(edata) + self.assertIsNotNone(edata) if edata is not None: if rep_msg_type == KRB_TGS_REP and not sent_fast: error_data = self.der_decode( @@ -2506,12 +2510,11 @@ class RawKerberosTest(TestCaseInTempDir): status = int.from_bytes(extended_error[:4], 'little') flags = int.from_bytes(extended_error[8:], 'little') - expected_status = kdc_exchange_dict['expected_status'] self.assertEqual(expected_status, status) self.assertEqual(3, flags) else: - self.assertIsNone(kdc_exchange_dict['expected_status']) + self.assertIsNone(expected_status) rep_padata = self.der_decode(edata, asn1Spec=krb5_asn1.METHOD_DATA()) -- 2.25.1 From 963db6229f95e2c5a05d9f66b55fa101338c94f9 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 16:10:07 +1300 Subject: [PATCH 094/162] tests/krb5: Add expect_claims parameter to kdc_exchange_dict BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 7cfc225b549108739bd86e222f2f35eb96af4ea3) --- python/samba/tests/krb5/raw_testcase.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 1a3aedbd436..0415f1ff6e6 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1961,6 +1961,7 @@ class RawKerberosTest(TestCaseInTempDir): pac_options=None, expect_edata=None, expect_pac=True, + expect_claims=True, to_rodc=False): if expected_error_mode == 0: expected_error_mode = () @@ -2008,6 +2009,7 @@ class RawKerberosTest(TestCaseInTempDir): 'pac_options': pac_options, 'expect_edata': expect_edata, 'expect_pac': expect_pac, + 'expect_claims': expect_claims, 'to_rodc': to_rodc } if callback_dict is None: @@ -2050,6 +2052,7 @@ class RawKerberosTest(TestCaseInTempDir): pac_options=None, expect_edata=None, expect_pac=True, + expect_claims=True, to_rodc=False): if expected_error_mode == 0: expected_error_mode = () @@ -2096,6 +2099,7 @@ class RawKerberosTest(TestCaseInTempDir): 'pac_options': pac_options, 'expect_edata': expect_edata, 'expect_pac': expect_pac, + 'expect_claims': expect_claims, 'to_rodc': to_rodc } if callback_dict is None: -- 2.25.1 From cc31f545638e8196d0ea7434b392339809c07def Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 16:15:26 +1300 Subject: [PATCH 095/162] tests/krb5: Check buffer types in PAC with STRICT_CHECKING=1 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit aa2e583fdea4fd93e4e71c54630e32a1035d1e2a) --- librpc/idl/krb5pac.idl | 3 ++ python/samba/tests/krb5/raw_testcase.py | 52 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl index 3239d7656b6..515150ab9cd 100644 --- a/librpc/idl/krb5pac.idl +++ b/librpc/idl/krb5pac.idl @@ -113,6 +113,9 @@ interface krb5pac PAC_TYPE_LOGON_NAME = 10, PAC_TYPE_CONSTRAINED_DELEGATION = 11, PAC_TYPE_UPN_DNS_INFO = 12, + PAC_TYPE_CLIENT_CLAIMS_INFO = 13, + PAC_TYPE_DEVICE_INFO = 14, + PAC_TYPE_DEVICE_CLAIMS_INFO = 15, PAC_TYPE_TICKET_CHECKSUM = 16 } PAC_TYPE; diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 0415f1ff6e6..320de0a4dbe 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2340,6 +2340,13 @@ class RawKerberosTest(TestCaseInTempDir): self.assertElementPresent(ticket_private, 'authorization-data', expect_empty=not expect_pac) + if expect_pac: + authorization_data = self.getElementValue(ticket_private, + 'authorization-data') + pac_data = self.get_pac(authorization_data) + + self.check_pac_buffers(pac_data, kdc_exchange_dict) + encpart_session_key = None if encpart_private is not None: self.assertElementPresent(encpart_private, 'key') @@ -2446,6 +2453,47 @@ class RawKerberosTest(TestCaseInTempDir): kdc_exchange_dict['rep_ticket_creds'] = ticket_creds + def check_pac_buffers(self, pac_data, kdc_exchange_dict): + pac = ndr_unpack(krb5pac.PAC_DATA, pac_data) + + rep_msg_type = kdc_exchange_dict['rep_msg_type'] + armor_tgt = kdc_exchange_dict['armor_tgt'] + + expected_sname = kdc_exchange_dict['expected_sname'] + expect_claims = kdc_exchange_dict['expect_claims'] + + expected_types = [krb5pac.PAC_TYPE_LOGON_INFO, + krb5pac.PAC_TYPE_SRV_CHECKSUM, + krb5pac.PAC_TYPE_KDC_CHECKSUM, + krb5pac.PAC_TYPE_LOGON_NAME, + krb5pac.PAC_TYPE_UPN_DNS_INFO] + + kdc_options = kdc_exchange_dict['kdc_options'] + pos = len(tuple(krb5_asn1.KDCOptions('cname-in-addl-tkt'))) - 1 + constrained_delegation = (pos < len(kdc_options) + and kdc_options[pos] == '1') + if constrained_delegation: + expected_types.append(krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION) + + if self.kdc_fast_support: + if expect_claims: + expected_types.append(krb5pac.PAC_TYPE_CLIENT_CLAIMS_INFO) + + if (rep_msg_type == KRB_TGS_REP + and armor_tgt is not None): + expected_types.append(krb5pac.PAC_TYPE_DEVICE_INFO) + expected_types.append(krb5pac.PAC_TYPE_DEVICE_CLAIMS_INFO) + + if not self.is_tgs(expected_sname): + expected_types.append(krb5pac.PAC_TYPE_TICKET_CHECKSUM) + + if self.strict_checking: + buffer_types = [pac_buffer.type + for pac_buffer in pac.buffers] + self.assertCountEqual(expected_types, buffer_types, + f'expected: {expected_types} ' + f'got: {buffer_types}') + def generic_check_kdc_error(self, kdc_exchange_dict, callback_dict, @@ -3397,6 +3445,10 @@ class RawKerberosTest(TestCaseInTempDir): return new_auth_data, old_pac + def get_pac(self, auth_data, expect_pac=True): + _, pac = self.replace_pac(auth_data, None, expect_pac) + return pac + def get_krbtgt_checksum_key(self): krbtgt_creds = self.get_krbtgt_creds() krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) -- 2.25.1 From 59b129bb590b4b9fd1625bd70e96fd360ca87913 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 16:26:54 +1300 Subject: [PATCH 096/162] tests/krb5: Check constrained delegation PAC buffer BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 0e232fa1c9e5760ae6b9a99b5e7aa5513b84aa8b) --- python/samba/tests/krb5/raw_testcase.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 320de0a4dbe..8144bd37b2f 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2053,6 +2053,8 @@ class RawKerberosTest(TestCaseInTempDir): expect_edata=None, expect_pac=True, expect_claims=True, + expected_proxy_target=None, + expected_transited_services=None, to_rodc=False): if expected_error_mode == 0: expected_error_mode = () @@ -2100,6 +2102,8 @@ class RawKerberosTest(TestCaseInTempDir): 'expect_edata': expect_edata, 'expect_pac': expect_pac, 'expect_claims': expect_claims, + 'expected_proxy_target': expected_proxy_target, + 'expected_transited_services': expected_transited_services, 'to_rodc': to_rodc } if callback_dict is None: @@ -2494,6 +2498,23 @@ class RawKerberosTest(TestCaseInTempDir): f'expected: {expected_types} ' f'got: {buffer_types}') + for pac_buffer in pac.buffers: + if pac_buffer.type == krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION: + expected_proxy_target = kdc_exchange_dict[ + 'expected_proxy_target'] + expected_transited_services = kdc_exchange_dict[ + 'expected_transited_services'] + + delegation_info = pac_buffer.info.info + + self.assertEqual(expected_proxy_target, + str(delegation_info.proxy_target)) + + transited_services = list(map( + str, delegation_info.transited_services)) + self.assertEqual(expected_transited_services, + transited_services) + def generic_check_kdc_error(self, kdc_exchange_dict, callback_dict, -- 2.25.1 From 1ea174685400761c982d9b1384e3472b59be2d74 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 16:41:23 +1300 Subject: [PATCH 097/162] tests/krb5: Save account SPN This is useful for testing delegation. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit bb58b4b58c66a6ada79e886dd0c44401e1c5878c) --- python/samba/tests/krb5/kdc_base_test.py | 1 + python/samba/tests/krb5/raw_testcase.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index d25fc0b42b2..70ab14786da 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -285,6 +285,7 @@ class KDCBaseTest(RawKerberosTest): else: creds.set_workstation('') creds.set_dn(ldb.Dn(samdb, dn)) + creds.set_spn(spn) # # Save the account name so it can be deleted in tearDownClass self.accounts.add(dn) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 8144bd37b2f..c34ffb848e1 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -365,6 +365,7 @@ class KerberosCredentials(Credentials): self.forced_salt = None self.dn = None + self.spn = None def set_as_supported_enctypes(self, value): self.as_supported_enctypes = int(value) @@ -467,6 +468,12 @@ class KerberosCredentials(Credentials): def get_dn(self): return self.dn + def set_spn(self, spn): + self.spn = spn + + def get_spn(self): + return self.spn + class KerberosTicketCreds: def __init__(self, ticket, session_key, -- 2.25.1 From a6bfa7318b4f466d08d290dedb1af580ff8e5f5a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 16:48:50 +1300 Subject: [PATCH 098/162] tests/krb5: Allow specifying options and expected flags when obtaining a ticket BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 34020766bb7094d1ab5d4fc4c0ee89ccb81f39f1) --- python/samba/tests/krb5/kdc_base_test.py | 31 +++++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 70ab14786da..34a23b3b876 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1164,7 +1164,7 @@ class KDCBaseTest(RawKerberosTest): def tgs_req(self, cname, sname, realm, ticket, key, etypes, expected_error_mode=0, padata=None, kdc_options=0, to_rodc=False, service_creds=None, expect_pac=True, - expect_edata=None): + expect_edata=None, expected_flags=None, unexpected_flags=None): '''Send a TGS-REQ, returns the response and the decrypted and decoded enc-part ''' @@ -1203,6 +1203,8 @@ class KDCBaseTest(RawKerberosTest): expected_srealm=realm, expected_sname=sname, expected_error_mode=expected_error_mode, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, check_error_fn=check_error_fn, check_rep_fn=check_rep_fn, check_kdc_private_fn=self.generic_check_kdc_private, @@ -1230,10 +1232,12 @@ class KDCBaseTest(RawKerberosTest): return rep, enc_part def get_service_ticket(self, tgt, target_creds, service='host', - to_rodc=False, fresh=False): + to_rodc=False, kdc_options=None, + expected_flags=None, unexpected_flags=None, + fresh=False): user_name = tgt.cname['name-string'][0] target_name = target_creds.get_username() - cache_key = (user_name, target_name, service, to_rodc) + cache_key = (user_name, target_name, service, to_rodc, kdc_options) if not fresh: ticket = self.tkt_cache.get(cache_key) @@ -1243,6 +1247,10 @@ class KDCBaseTest(RawKerberosTest): etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) + if kdc_options is None: + kdc_options = '0' + kdc_options = krb5_asn1.KDCOptions(kdc_options) + key = tgt.session_key ticket = tgt.ticket @@ -1255,7 +1263,10 @@ class KDCBaseTest(RawKerberosTest): rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype, to_rodc=to_rodc, - service_creds=target_creds) + service_creds=target_creds, + kdc_options=kdc_options, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags) service_ticket = rep['ticket'] @@ -1309,11 +1320,11 @@ class KDCBaseTest(RawKerberosTest): self.TicketDecryptionKey_from_creds(krbtgt_creds)) if kdc_options is None: - kdc_options = krb5_asn1.KDCOptions('forwardable,' - 'renewable,' - 'canonicalize,' - 'renewable-ok') - kdc_options = str(kdc_options) + kdc_options = ('forwardable,' + 'renewable,' + 'canonicalize,' + 'renewable-ok') + kdc_options = krb5_asn1.KDCOptions(kdc_options) pac_options = '1' # supports claims @@ -1370,6 +1381,8 @@ class KDCBaseTest(RawKerberosTest): expected_srealm=expected_realm, expected_sname=expected_sname, expected_salt=salt, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, expected_supported_etypes=expected_etypes, etypes=etype, padata=padata, -- 2.25.1 From e4ca6061acb1ce2c2e576dd5098a44caf8c01811 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 16:52:01 +1300 Subject: [PATCH 099/162] tests/krb5: Supply supported account enctypes in tgs_req() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 248249dc0acac89d1495c3572cbd2cbe8bdca362) --- python/samba/tests/krb5/kdc_base_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 34a23b3b876..93951586cc7 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1181,8 +1181,10 @@ class KDCBaseTest(RawKerberosTest): if service_creds is not None: decryption_key = self.TicketDecryptionKey_from_creds( service_creds) + expected_supported_etypes = service_creds.tgs_supported_enctypes else: decryption_key = None + expected_supported_etypes = None if not expected_error_mode: check_error_fn = None @@ -1205,6 +1207,7 @@ class KDCBaseTest(RawKerberosTest): expected_error_mode=expected_error_mode, expected_flags=expected_flags, unexpected_flags=unexpected_flags, + expected_supported_etypes=expected_supported_etypes, check_error_fn=check_error_fn, check_rep_fn=check_rep_fn, check_kdc_private_fn=self.generic_check_kdc_private, -- 2.25.1 From 66ec4236cadd1bff830b9dd4838c0fa7aa12c0aa Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 30 Sep 2021 16:53:35 +1300 Subject: [PATCH 100/162] tests/krb5: Add parameter to enforce presence of ticket checksums This allows existing tests to pass before this functionality is implemented. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ef24fe982d750a42be81808379b0254d8488c559) --- python/samba/tests/krb5/raw_testcase.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index c34ffb848e1..72a39b23b0e 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1942,6 +1942,7 @@ class RawKerberosTest(TestCaseInTempDir): expected_flags=None, unexpected_flags=None, ticket_decryption_key=None, + expect_ticket_checksum=None, generate_fast_fn=None, generate_fast_armor_fn=None, generate_fast_padata_fn=None, @@ -1990,6 +1991,7 @@ class RawKerberosTest(TestCaseInTempDir): 'expected_flags': expected_flags, 'unexpected_flags': unexpected_flags, 'ticket_decryption_key': ticket_decryption_key, + 'expect_ticket_checksum': expect_ticket_checksum, 'generate_fast_fn': generate_fast_fn, 'generate_fast_armor_fn': generate_fast_armor_fn, 'generate_fast_padata_fn': generate_fast_padata_fn, @@ -2034,6 +2036,7 @@ class RawKerberosTest(TestCaseInTempDir): expected_flags=None, unexpected_flags=None, ticket_decryption_key=None, + expect_ticket_checksum=None, generate_fast_fn=None, generate_fast_armor_fn=None, generate_fast_padata_fn=None, @@ -2083,6 +2086,7 @@ class RawKerberosTest(TestCaseInTempDir): 'expected_flags': expected_flags, 'unexpected_flags': unexpected_flags, 'ticket_decryption_key': ticket_decryption_key, + 'expect_ticket_checksum': expect_ticket_checksum, 'generate_fast_fn': generate_fast_fn, 'generate_fast_armor_fn': generate_fast_armor_fn, 'generate_fast_padata_fn': generate_fast_padata_fn, @@ -2459,8 +2463,15 @@ class RawKerberosTest(TestCaseInTempDir): ticket_private=ticket_private, encpart_private=encpart_private) + # TODO: This parameter should be removed when all service tickets are + # issued with ticket checksums. + expect_ticket_checksum = kdc_exchange_dict['expect_ticket_checksum'] + if expect_ticket_checksum: + self.assertIsNotNone(ticket_decryption_key) + if ticket_decryption_key is not None: - self.verify_ticket(ticket_creds, krbtgt_key, expect_pac=expect_pac) + self.verify_ticket(ticket_creds, krbtgt_key, expect_pac=expect_pac, + expect_ticket_checksum=expect_ticket_checksum) kdc_exchange_dict['rep_ticket_creds'] = ticket_creds @@ -3083,7 +3094,8 @@ class RawKerberosTest(TestCaseInTempDir): ticket_blob) self.assertEqual(expected_checksum, checksum) - def verify_ticket(self, ticket, krbtgt_key, expect_pac=True): + def verify_ticket(self, ticket, krbtgt_key, expect_pac=True, + expect_ticket_checksum=True): # Check if the ticket is a TGT. sname = ticket.ticket['sname'] is_tgt = self.is_tgs(sname) @@ -3182,8 +3194,10 @@ class RawKerberosTest(TestCaseInTempDir): ticket_checksum, ticket_ctype = checksums.get( krb5pac.PAC_TYPE_TICKET_CHECKSUM, (None, None)) - if self.strict_checking: + if expect_ticket_checksum: self.assertIsNotNone(ticket_checksum) + elif expect_ticket_checksum is False: + self.assertIsNone(ticket_checksum) if ticket_checksum is not None: enc_part['authorization-data'] = auth_data enc_part = self.der_encode(enc_part, -- 2.25.1 From 2572b6ce3efd78201aed6bc84d1e3957d3e4e81a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 14 Oct 2021 16:43:05 +1300 Subject: [PATCH 101/162] tests/krb5: Add compatability tests for ticket checksums BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett [abartlet@samba.org: Backported from ec4b264bdf9ab64a728212580b344fbf35c3c673 to Samba 4.14 due to conflicts in knownfail as the test which crashes older MIT KDC versions is omitted] --- .../samba/tests/krb5/compatability_tests.py | 44 ++++++++++++++++++- selftest/knownfail_heimdal_kdc | 6 ++- source4/selftest/tests.py | 7 ++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/compatability_tests.py b/python/samba/tests/krb5/compatability_tests.py index cd67549212a..0da72796894 100755 --- a/python/samba/tests/krb5/compatability_tests.py +++ b/python/samba/tests/krb5/compatability_tests.py @@ -23,7 +23,7 @@ import os sys.path.insert(0, "bin/python") os.environ["PYTHONUNBUFFERED"] = "1" -from samba.tests.krb5.raw_testcase import RawKerberosTest +from samba.tests.krb5.kdc_base_test import KDCBaseTest import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1 from samba.tests.krb5.rfc4120_constants import ( AES128_CTS_HMAC_SHA1_96, @@ -50,7 +50,7 @@ MIT_ENC_AS_REP_PART_TYPE_TAG = 0x7A ENC_PA_REP_FLAG = 0x00010000 -class SimpleKerberosTests(RawKerberosTest): +class SimpleKerberosTests(KDCBaseTest): def setUp(self): super(SimpleKerberosTests, self).setUp() @@ -120,6 +120,46 @@ class SimpleKerberosTests(RawKerberosTest): self.fail( "(Heimdal) Salt populated for ARCFOUR_HMAC_MD5 encryption") + def test_heimdal_ticket_signature(self): + # Ensure that a DC correctly issues tickets signed with its krbtgt key. + user_creds = self.get_client_creds() + target_creds = self.get_service_creds() + + krbtgt_creds = self.get_krbtgt_creds() + key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + + # Get a TGT from the DC. + tgt = self.get_tgt(user_creds) + + # Ensure the PAC contains the expected checksums. + self.verify_ticket(tgt, key) + + # Get a service ticket from the DC. + service_ticket = self.get_service_ticket(tgt, target_creds) + + # Ensure the PAC contains the expected checksums. + self.verify_ticket(service_ticket, key, expect_ticket_checksum=True) + + def test_mit_ticket_signature(self): + # Ensure that a DC does not issue tickets signed with its krbtgt key. + user_creds = self.get_client_creds() + target_creds = self.get_service_creds() + + krbtgt_creds = self.get_krbtgt_creds() + key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + + # Get a TGT from the DC. + tgt = self.get_tgt(user_creds) + + # Ensure the PAC contains the expected checksums. + self.verify_ticket(tgt, key) + + # Get a service ticket from the DC. + service_ticket = self.get_service_ticket(tgt, target_creds) + + # Ensure the PAC does not contain the expected checksums. + self.verify_ticket(service_ticket, key, expect_ticket_checksum=False) + def as_pre_auth_req(self, creds, etypes): user = creds.get_username() realm = creds.get_realm() diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 80b8224f015..6eb667f8969 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -1,7 +1,7 @@ # # We expect all the MIT specific compatability tests to fail on heimdal # kerberos -^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_mit_ +^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_mit_(?!ticket_signature) # # Heimdal currently fails the following MS-KILE client principal lookup # tests @@ -121,3 +121,7 @@ ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_outer_no_sname.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_no_sname.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_sname.ad_dc +# +# Heimdal currently does not generate ticket signatures +# +^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_heimdal_ticket_signature diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 423f48b6921..dfd5b271cd2 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -1390,7 +1390,12 @@ planpythontestsuite("ad_dc", "samba.tests.krb5.as_canonicalization_tests", 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD' }) -planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests") +planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests", + environ={ + 'ADMIN_USERNAME': '$USERNAME', + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0', + }) planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests") planpythontestsuite( "ad_dc", -- 2.25.1 From 50f5ba15889f33153d6e89a3d998a266f408e638 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 11 Oct 2021 14:37:03 +1300 Subject: [PATCH 102/162] tests/krb5: Use correct principal name type BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 687c8f94c68af9f1e44771dfd7219eeb41382bba) --- python/samba/tests/krb5/fast_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/fast_tests.py b/python/samba/tests/krb5/fast_tests.py index 28fe0686335..1cdfd5e20c4 100755 --- a/python/samba/tests/krb5/fast_tests.py +++ b/python/samba/tests/krb5/fast_tests.py @@ -43,6 +43,7 @@ from samba.tests.krb5.rfc4120_constants import ( KRB_AS_REP, KRB_TGS_REP, NT_PRINCIPAL, + NT_SRV_HST, NT_SRV_INST, PADATA_FX_COOKIE, PADATA_FX_FAST, @@ -1136,7 +1137,7 @@ class FAST_Tests(KDCBaseTest): target_realm = target_creds.get_realm() target_service = 'host' target_sname = self.PrincipalName_create( - name_type=NT_SRV_INST, names=[target_service, target_username]) + name_type=NT_SRV_HST, names=[target_service, target_username]) target_decryption_key = self.TicketDecryptionKey_from_creds( target_creds) target_etypes = target_creds.tgs_supported_enctypes -- 2.25.1 From 4c6bf1bf929d7edbb40b1959618661b5d459186c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 11 Oct 2021 14:39:26 +1300 Subject: [PATCH 103/162] tests/krb5: Clarify checksum type assertion message BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ee2b7e2c77f021984ec583fa0c4c756979197b0f) --- python/samba/tests/krb5/raw_testcase.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 72a39b23b0e..e52eb5ae5b9 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -248,7 +248,8 @@ class Krb5EncryptionKey: def verify_checksum(self, usage, plaintext, ctype, cksum): if self.ctype != ctype: - raise AssertionError(f'{self.ctype} != {ctype}') + raise AssertionError(f'key checksum type ({self.ctype}) != ' + f'checksum type ({ctype})') kcrypto.verify_checksum(ctype, self.key, -- 2.25.1 From 980992e8c8ea3bf2c30c565dc133bf61cb7d2051 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 11 Oct 2021 16:15:43 +1300 Subject: [PATCH 104/162] tests/krb5: Fix padata checking at functional level 2003 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 72265227e9c2037b63cdfb01a456a86ac8932f59) --- python/samba/tests/krb5/raw_testcase.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index e52eb5ae5b9..bb9d414da5b 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2661,11 +2661,10 @@ class RawKerberosTest(TestCaseInTempDir): if kcrypto.Enctype.RC4 in proposed_etypes: expect_etype_info = True for etype in proposed_etypes: - if etype in (kcrypto.Enctype.AES256, kcrypto.Enctype.AES128): - expect_etype_info = False if etype not in client_as_etypes: continue if etype in (kcrypto.Enctype.AES256, kcrypto.Enctype.AES128): + expect_etype_info = False if etype > expected_aes_type: expected_aes_type = etype if etype in (kcrypto.Enctype.RC4,) and error_code != 0: @@ -2865,7 +2864,8 @@ class RawKerberosTest(TestCaseInTempDir): else: self.assertIsNone(etype_info2) if expect_etype_info: - self.assertIsNotNone(etype_info) + if self.strict_checking: + self.assertIsNotNone(etype_info) else: if self.strict_checking: self.assertIsNone(etype_info) -- 2.25.1 From a5bc3d294ca7172582730cdc23b12ddfa65ef11d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 12 Oct 2021 11:34:59 +1300 Subject: [PATCH 105/162] tests/krb5: Add environment variable to specify KDC FAST support BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett [abartlet@samba.org backportd from commit 238f52bad811688624e9fd4b1595266e2149094a because tests.py changed in more recent releases with new tests nearby] --- python/samba/tests/krb5/raw_testcase.py | 6 +++- source4/selftest/tests.py | 37 +++++++++++++++++-------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index bb9d414da5b..fbddb7f83b1 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -568,7 +568,11 @@ class RawKerberosTest(TestCaseInTempDir): # obtained. cls.creds_dict = {} - cls.kdc_fast_support = False + kdc_fast_support = samba.tests.env_get_var_value('FAST_SUPPORT', + allow_missing=True) + if kdc_fast_support is None: + kdc_fast_support = '0' + cls.kdc_fast_support = bool(int(kdc_fast_support)) def setUp(self): super().setUp() diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index dfd5b271cd2..ae8da7c8e34 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -787,39 +787,47 @@ planoldpythontestsuite("nt4_dc", "samba.tests.netbios", extra_args=['-U"$USERNAM planoldpythontestsuite("ad_dc:local", "samba.tests.gpo", extra_args=['-U"$USERNAME%$PASSWORD"']) planoldpythontestsuite("ad_dc:local", "samba.tests.dckeytab", extra_args=['-U"$USERNAME%$PASSWORD"']) +have_fast_support = int('SAMBA_USES_MITKDC' in config_hash) planoldpythontestsuite("none", "samba.tests.krb5.kcrypto") planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.simple_tests", - environ={'SERVICE_USERNAME':'$SERVER'}) + environ={'SERVICE_USERNAME':'$SERVER', + 'FAST_SUPPORT': have_fast_support}) planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests", environ={'SERVICE_USERNAME':'srv_account', 'SERVICE_PASSWORD':'$PASSWORD', - 'FOR_USER':'$USERNAME'}) + 'FOR_USER':'$USERNAME', + 'FAST_SUPPORT': have_fast_support}) -planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests") +planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests", + environ={'FAST_SUPPORT': have_fast_support}) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ccache", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', - 'STRICT_CHECKING': '0' + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', - 'STRICT_CHECKING': '0' + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_rpc", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', - 'STRICT_CHECKING': '0' + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', - 'STRICT_CHECKING': '0' + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) for env in ["ad_dc", smbv1_disabled_testenv]: @@ -1368,6 +1376,7 @@ for env in ["fl2008r2dc", "fl2003dc"]: 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) @@ -1388,22 +1397,26 @@ for env in ["rodc", "promoted_dc", "fl2000dc", "fl2008r2dc"]: planpythontestsuite("ad_dc", "samba.tests.krb5.as_canonicalization_tests", environ={ 'ADMIN_USERNAME': '$USERNAME', - 'ADMIN_PASSWORD': '$PASSWORD' + 'ADMIN_PASSWORD': '$PASSWORD', + 'FAST_SUPPORT': have_fast_support }) planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support, }) -planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests") +planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests", + environ={'FAST_SUPPORT': have_fast_support}) planpythontestsuite( "ad_dc", "samba.tests.krb5.kdc_tgs_tests", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', - 'STRICT_CHECKING': '0' + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) planpythontestsuite( "ad_dc", @@ -1412,6 +1425,7 @@ planpythontestsuite( 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) planpythontestsuite( "ad_dc", @@ -1419,7 +1433,8 @@ planpythontestsuite( environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', - 'STRICT_CHECKING': '0' + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support }) for env in [ -- 2.25.1 From bb248ff2b2458da767b193aa78cfdbbeb13a0ea7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 11 Oct 2021 14:45:45 +1300 Subject: [PATCH 106/162] tests/krb5: Check padata types when STRICT_CHECKING=0 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett [abartlet@samba.org backported from commit bd22dcd9cc4dfda827f892224eb2da4a16564176 to Samba 4.14 due to conflicts in knownfail as the test which crashes older MIT KDC versions is omitted] --- python/samba/tests/krb5/raw_testcase.py | 25 +++++++++++++++++++++---- selftest/knownfail_mit_kdc | 9 +++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index fbddb7f83b1..dbcff787f70 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1079,6 +1079,20 @@ class RawKerberosTest(TestCaseInTempDir): f"'{unexpected.namedValues[i]}' " f"unexpected in {v}") + def assertSequenceElementsEqual(self, expected, got, *, + require_strict=None): + if self.strict_checking: + self.assertEqual(expected, got) + else: + fail_msg = f'expected: {expected} got: {got}' + + if require_strict is not None: + fail_msg += f' (ignoring: {require_strict})' + expected = (x for x in expected if x not in require_strict) + got = (x for x in got if x not in require_strict) + + self.assertCountEqual(expected, got, fail_msg) + def get_KerberosTimeWithUsec(self, epoch=None, offset=None): if epoch is None: epoch = time.time() @@ -2714,10 +2728,13 @@ class RawKerberosTest(TestCaseInTempDir): expected_patypes += (PADATA_FX_FAST,) expected_patypes += (PADATA_FX_COOKIE,) - if self.strict_checking: - for i, patype in enumerate(expected_patypes): - self.assertElementEqual(rep_padata[i], 'padata-type', patype) - self.assertEqual(len(rep_padata), len(expected_patypes)) + got_patypes = tuple(pa['padata-type'] for pa in rep_padata) + self.assertSequenceElementsEqual(expected_patypes, got_patypes, + require_strict={PADATA_FX_COOKIE, + PADATA_FX_FAST, + PADATA_PAC_OPTIONS, + PADATA_PK_AS_REP_19, + PADATA_PK_AS_REQ}) etype_info2 = None etype_info = None diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc index f167c2bf856..4e0b20c5c80 100644 --- a/selftest/knownfail_mit_kdc +++ b/selftest/knownfail_mit_kdc @@ -290,6 +290,11 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ ^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_b ^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_c ^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_6_c +# +# MIT currently fails some as_req_no_preauth tests. +# +^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth.*aes.*rc4.*fl2003dc +^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth.*rc4.*aes.*fl2003dc # Differences in our KDC compared to windows # ^samba4.krb5.kdc .*.as-req-pac-request # We should reply to a request for a PAC over UDP with KRB5KRB_ERR_RESPONSE_TOO_BIG unconditionally @@ -304,6 +309,9 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_authdata_fast_not_used.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_enc_timestamp.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_clock_skew.ad_dc +^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_no_fast.ad_dc +^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_wrong_key.ad_dc +^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_wrong_key_kdc.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_tgt.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_tgt_mach.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_armor.ad_dc @@ -318,5 +326,6 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_no_sname.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_sname.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_no_sname.ad_dc +^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_fast_no_etypes.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_no_sname.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_no_sname.ad_dc -- 2.25.1 From 4f6ca6e7c6b2e89aa8aef86bbad1dddf1381581b Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 11 Oct 2021 14:48:03 +1300 Subject: [PATCH 107/162] tests/krb5: Check logon name in PAC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit e7c39cc44f2e16aecb01c0afc195911a474ef0b9) --- python/samba/tests/krb5/raw_testcase.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index dbcff787f70..b0cd2bfdf0f 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2552,6 +2552,12 @@ class RawKerberosTest(TestCaseInTempDir): self.assertEqual(expected_transited_services, transited_services) + elif pac_buffer.type == krb5pac.PAC_TYPE_LOGON_NAME: + expected_cname = kdc_exchange_dict['expected_cname'] + account_name = expected_cname['name-string'][0] + + self.assertEqual(account_name, pac_buffer.info.account_name) + def generic_check_kdc_error(self, kdc_exchange_dict, callback_dict, -- 2.25.1 From b2fa01bcae41c7cf6c0e474eaa2833e78ba1a7b0 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 11 Oct 2021 14:49:34 +1300 Subject: [PATCH 108/162] tests/krb5: Simplify padata checking BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit cf3ca6ac4567d7c7954ea4ecc8cc9dd5effcc094) --- python/samba/tests/krb5/raw_testcase.py | 169 ++++++------------------ 1 file changed, 41 insertions(+), 128 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index b0cd2bfdf0f..b51ad499192 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2742,73 +2742,32 @@ class RawKerberosTest(TestCaseInTempDir): PADATA_PK_AS_REP_19, PADATA_PK_AS_REQ}) - etype_info2 = None - etype_info = None - enc_timestamp = None - enc_challenge = None - pk_as_req = None - pk_as_rep19 = None - fast_cookie = None - fast_error = None - fx_fast = None - pac_options = None - for pa in rep_padata: - patype = self.getElementValue(pa, 'padata-type') - pavalue = self.getElementValue(pa, 'padata-value') - if patype == PADATA_ETYPE_INFO2: - self.assertIsNone(etype_info2) - etype_info2 = self.der_decode(pavalue, - asn1Spec=krb5_asn1.ETYPE_INFO2()) - continue - if patype == PADATA_ETYPE_INFO: - self.assertIsNone(etype_info) - etype_info = self.der_decode(pavalue, - asn1Spec=krb5_asn1.ETYPE_INFO()) - continue - if patype == PADATA_ENC_TIMESTAMP: - self.assertIsNone(enc_timestamp) - enc_timestamp = pavalue - self.assertEqual(len(enc_timestamp), 0) - continue - if patype == PADATA_ENCRYPTED_CHALLENGE: - self.assertIsNone(enc_challenge) - enc_challenge = pavalue - continue - if patype == PADATA_PK_AS_REQ: - self.assertIsNone(pk_as_req) - pk_as_req = pavalue - self.assertEqual(len(pk_as_req), 0) - continue - if patype == PADATA_PK_AS_REP_19: - self.assertIsNone(pk_as_rep19) - pk_as_rep19 = pavalue - self.assertEqual(len(pk_as_rep19), 0) - continue - if patype == PADATA_FX_COOKIE: - self.assertIsNone(fast_cookie) - fast_cookie = pavalue - self.assertIsNotNone(fast_cookie) - continue - if patype == PADATA_FX_ERROR: - self.assertIsNone(fast_error) - fast_error = pavalue - self.assertIsNotNone(fast_error) - continue - if patype == PADATA_FX_FAST: - self.assertIsNone(fx_fast) - fx_fast = pavalue - self.assertEqual(len(fx_fast), 0) - continue - if patype == PADATA_PAC_OPTIONS: - self.assertIsNone(pac_options) - pac_options = self.der_decode( - pavalue, - asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) - continue + if not expected_patypes: + return None + + pa_dict = self.get_pa_dict(rep_padata) + + enc_timestamp = pa_dict.get(PADATA_ENC_TIMESTAMP) + if enc_timestamp is not None: + self.assertEqual(len(enc_timestamp), 0) + + pk_as_req = pa_dict.get(PADATA_PK_AS_REQ) + if pk_as_req is not None: + self.assertEqual(len(pk_as_req), 0) + + pk_as_rep19 = pa_dict.get(PADATA_PK_AS_REP_19) + if pk_as_rep19 is not None: + self.assertEqual(len(pk_as_rep19), 0) + fx_fast = pa_dict.get(PADATA_FX_FAST) + if fx_fast is not None: + self.assertEqual(len(fx_fast), 0) + + fast_cookie = pa_dict.get(PADATA_FX_COOKIE) if fast_cookie is not None: kdc_exchange_dict['fast_cookie'] = fast_cookie + fast_error = pa_dict.get(PADATA_FX_ERROR) if fast_error is not None: fast_error = self.der_decode(fast_error, asn1Spec=krb5_asn1.KRB_ERROR()) @@ -2817,9 +2776,14 @@ class RawKerberosTest(TestCaseInTempDir): fast_error, inner=True) + pac_options = pa_dict.get(PADATA_PAC_OPTIONS) if pac_options is not None: + pac_options = self.der_decode( + pac_options, + asn1Spec=krb5_asn1.PA_PAC_OPTIONS()) self.assertElementEqual(pac_options, 'options', sent_pac_options) + enc_challenge = pa_dict.get(PADATA_ENCRYPTED_CHALLENGE) if enc_challenge is not None: if not sent_enc_challenge: self.assertEqual(len(enc_challenge), 0) @@ -2862,52 +2826,21 @@ class RawKerberosTest(TestCaseInTempDir): self.assertLess(current_time - 300, rep_time) self.assertLess(rep_time, current_time + 300) - if all(etype not in client_as_etypes or etype not in proposed_etypes - for etype in (kcrypto.Enctype.AES256, - kcrypto.Enctype.AES128, - kcrypto.Enctype.RC4)): - self.assertIsNone(etype_info2) - self.assertIsNone(etype_info) - if rep_msg_type == KRB_AS_REP: - if self.strict_checking: - if sent_fast: - self.assertIsNotNone(enc_challenge) - self.assertIsNone(enc_timestamp) - else: - self.assertIsNotNone(enc_timestamp) - self.assertIsNone(enc_challenge) - self.assertIsNotNone(pk_as_req) - self.assertIsNotNone(pk_as_rep19) - else: - self.assertIsNone(enc_timestamp) - self.assertIsNone(enc_challenge) - self.assertIsNone(pk_as_req) - self.assertIsNone(pk_as_rep19) - return None - - if error_code != KDC_ERR_GENERIC: - if self.strict_checking: - self.assertIsNotNone(etype_info2) - else: - self.assertIsNone(etype_info2) - if expect_etype_info: - if self.strict_checking: - self.assertIsNotNone(etype_info) - else: - if self.strict_checking: - self.assertIsNone(etype_info) - if unexpect_etype_info: - self.assertIsNone(etype_info) - - if error_code != KDC_ERR_GENERIC and self.strict_checking: + etype_info2 = pa_dict.get(PADATA_ETYPE_INFO2) + if etype_info2 is not None: + etype_info2 = self.der_decode(etype_info2, + asn1Spec=krb5_asn1.ETYPE_INFO2()) self.assertGreaterEqual(len(etype_info2), 1) - self.assertEqual(len(etype_info2), len(expect_etype_info2)) + if self.strict_checking: + self.assertEqual(len(etype_info2), len(expect_etype_info2)) for i in range(0, len(etype_info2)): e = self.getElementValue(etype_info2[i], 'etype') - self.assertEqual(e, expect_etype_info2[i]) + if self.strict_checking: + self.assertEqual(e, expect_etype_info2[i]) salt = self.getElementValue(etype_info2[i], 'salt') if e == kcrypto.Enctype.RC4: - self.assertIsNone(salt) + if self.strict_checking: + self.assertIsNone(salt) else: self.assertIsNotNone(salt) expected_salt = kdc_exchange_dict['expected_salt'] @@ -2916,7 +2849,11 @@ class RawKerberosTest(TestCaseInTempDir): s2kparams = self.getElementValue(etype_info2[i], 's2kparams') if self.strict_checking: self.assertIsNone(s2kparams) + + etype_info = pa_dict.get(PADATA_ETYPE_INFO) if etype_info is not None: + etype_info = self.der_decode(etype_info, + asn1Spec=krb5_asn1.ETYPE_INFO()) self.assertEqual(len(etype_info), 1) e = self.getElementValue(etype_info[0], 'etype') self.assertEqual(e, kcrypto.Enctype.RC4) @@ -2926,30 +2863,6 @@ class RawKerberosTest(TestCaseInTempDir): self.assertIsNotNone(salt) self.assertEqual(len(salt), 0) - if error_code not in (KDC_ERR_PREAUTH_FAILED, - KDC_ERR_GENERIC): - if sent_fast: - self.assertIsNotNone(enc_challenge) - if self.strict_checking: - self.assertIsNone(enc_timestamp) - else: - self.assertIsNotNone(enc_timestamp) - if self.strict_checking: - self.assertIsNone(enc_challenge) - if not sent_enc_challenge: - if self.strict_checking: - self.assertIsNotNone(pk_as_req) - self.assertIsNotNone(pk_as_rep19) - else: - self.assertIsNone(pk_as_req) - self.assertIsNone(pk_as_rep19) - else: - if self.strict_checking: - self.assertIsNone(enc_timestamp) - self.assertIsNone(enc_challenge) - self.assertIsNone(pk_as_req) - self.assertIsNone(pk_as_rep19) - return etype_info2 def generate_simple_fast(self, -- 2.25.1 From 3ef3de37f21877d154594a366a048e3afc449332 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 11:48:41 +1300 Subject: [PATCH 109/162] tests/krb5: Disable debugging output for tests This reduces the time spent running the tests in a testenv. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit dfd613661eec4b81e162f2d86a8fa9266c2fdc03) --- python/samba/tests/krb5/as_canonicalization_tests.py | 4 ++-- python/samba/tests/krb5/as_req_tests.py | 4 ++-- python/samba/tests/krb5/compatability_tests.py | 4 ++-- python/samba/tests/krb5/kdc_tests.py | 4 ++-- python/samba/tests/krb5/kdc_tgs_tests.py | 4 ++-- python/samba/tests/krb5/s4u_tests.py | 4 ++-- python/samba/tests/krb5/simple_tests.py | 4 ++-- python/samba/tests/krb5/test_ccache.py | 4 ++-- python/samba/tests/krb5/test_ldap.py | 4 ++-- python/samba/tests/krb5/test_rpc.py | 4 ++-- python/samba/tests/krb5/test_smb.py | 4 ++-- python/samba/tests/krb5/xrealm_tests.py | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/python/samba/tests/krb5/as_canonicalization_tests.py b/python/samba/tests/krb5/as_canonicalization_tests.py index 29d8cf418f5..9538d0ae3cf 100755 --- a/python/samba/tests/krb5/as_canonicalization_tests.py +++ b/python/samba/tests/krb5/as_canonicalization_tests.py @@ -427,8 +427,8 @@ class KerberosASCanonicalizationTests(KDCBaseTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/as_req_tests.py b/python/samba/tests/krb5/as_req_tests.py index 8d9b90fee69..7d7baaebf24 100755 --- a/python/samba/tests/krb5/as_req_tests.py +++ b/python/samba/tests/krb5/as_req_tests.py @@ -198,8 +198,8 @@ class AsReqKerberosTests(KDCBaseTest): self.assertIsNotNone(as_rep) if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/compatability_tests.py b/python/samba/tests/krb5/compatability_tests.py index 0da72796894..ed2dc565b6d 100755 --- a/python/samba/tests/krb5/compatability_tests.py +++ b/python/samba/tests/krb5/compatability_tests.py @@ -261,7 +261,7 @@ class SimpleKerberosTests(KDCBaseTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/kdc_tests.py b/python/samba/tests/krb5/kdc_tests.py index 928f3c25c0f..b7c8566a1ec 100755 --- a/python/samba/tests/krb5/kdc_tests.py +++ b/python/samba/tests/krb5/kdc_tests.py @@ -222,7 +222,7 @@ class KdcTests(RawKerberosTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py index 2b55ba8a376..3075cc6b0a9 100755 --- a/python/samba/tests/krb5/kdc_tgs_tests.py +++ b/python/samba/tests/krb5/kdc_tgs_tests.py @@ -211,7 +211,7 @@ class KdcTgsTests(KDCBaseTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py index 57575f0595d..bbddef4d6e0 100755 --- a/python/samba/tests/krb5/s4u_tests.py +++ b/python/samba/tests/krb5/s4u_tests.py @@ -197,7 +197,7 @@ class S4UKerberosTests(RawKerberosTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/simple_tests.py b/python/samba/tests/krb5/simple_tests.py index 795d753b4f7..3cd3b17bb31 100755 --- a/python/samba/tests/krb5/simple_tests.py +++ b/python/samba/tests/krb5/simple_tests.py @@ -179,7 +179,7 @@ class SimpleKerberosTests(RawKerberosTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/test_ccache.py b/python/samba/tests/krb5/test_ccache.py index feb7a7bd9be..c44ea02d504 100755 --- a/python/samba/tests/krb5/test_ccache.py +++ b/python/samba/tests/krb5/test_ccache.py @@ -129,7 +129,7 @@ class CcacheTests(KDCBaseTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/test_ldap.py b/python/samba/tests/krb5/test_ldap.py index d304fb9d71e..95b2d24221a 100755 --- a/python/samba/tests/krb5/test_ldap.py +++ b/python/samba/tests/krb5/test_ldap.py @@ -90,7 +90,7 @@ class LdapTests(KDCBaseTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/test_rpc.py b/python/samba/tests/krb5/test_rpc.py index 324b57f2847..40ac6df7a35 100755 --- a/python/samba/tests/krb5/test_rpc.py +++ b/python/samba/tests/krb5/test_rpc.py @@ -73,7 +73,7 @@ class RpcTests(KDCBaseTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/test_smb.py b/python/samba/tests/krb5/test_smb.py index 45d4fe5e0c1..eebc9a9d4fe 100755 --- a/python/samba/tests/krb5/test_smb.py +++ b/python/samba/tests/krb5/test_smb.py @@ -104,7 +104,7 @@ class SmbTests(KDCBaseTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() diff --git a/python/samba/tests/krb5/xrealm_tests.py b/python/samba/tests/krb5/xrealm_tests.py index 073cb755b46..73a6b3cf52d 100755 --- a/python/samba/tests/krb5/xrealm_tests.py +++ b/python/samba/tests/krb5/xrealm_tests.py @@ -181,7 +181,7 @@ class XrealmKerberosTests(RawKerberosTest): if __name__ == "__main__": - global_asn1_print = True - global_hexdump = True + global_asn1_print = False + global_hexdump = False import unittest unittest.main() -- 2.25.1 From c9222f4faf454e72a868fcaf75f85b44fc4cdce7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 5 Oct 2021 19:47:22 +1300 Subject: [PATCH 110/162] tests/krb5: Provide clearer assertion messages for test failures BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 5233f002000f196875af488b4f4d1df26fca90de) --- python/samba/tests/krb5/raw_testcase.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index b51ad499192..188a54451d3 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -1942,7 +1942,12 @@ class RawKerberosTest(TestCaseInTempDir): self.assertIsNone(check_error_fn) self.assertEqual(0, len(expected_error_mode)) self.assertIsNotNone(expected_msg_type) - self.assertEqual(msg_type, expected_msg_type) + if msg_type == KRB_ERROR: + error_code = self.getElementValue(rep, 'error-code') + fail_msg = f'Got unexpected error: {error_code}' + else: + fail_msg = f'Expected to fail with error: {expected_error_mode}' + self.assertEqual(msg_type, expected_msg_type, fail_msg) if msg_type == KRB_ERROR: return check_error_fn(kdc_exchange_dict, -- 2.25.1 From e38096812777ce3109b1122f181e7614963b5704 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 5 Oct 2021 16:32:01 +1300 Subject: [PATCH 111/162] tests/krb5: Fix sha1 checksum type Previously, sha1 signatures were being designated as rsa-md5-des3 signatures. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ebe729786806c69e95b26ffc410e887e203accb8) --- python/samba/tests/krb5/kcrypto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/kcrypto.py b/python/samba/tests/krb5/kcrypto.py index 2a72969de00..a919b785ad1 100755 --- a/python/samba/tests/krb5/kcrypto.py +++ b/python/samba/tests/krb5/kcrypto.py @@ -81,8 +81,8 @@ class Cksumtype(object): MD4_DES = 3 MD5 = 7 MD5_DES = 8 - SHA1 = 9 SHA1_DES3 = 12 + SHA1 = 14 SHA1_AES128 = 15 SHA1_AES256 = 16 HMAC_MD5 = -138 -- 2.25.1 From 0d6554253af915680d9abb7cb519148201ca6589 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 13 Oct 2021 12:26:22 +1300 Subject: [PATCH 112/162] selftest/dbcheck: Fix up RODC one-way links Test accounts were replicated to the RODC and then deleted, causing state links to remain in the database. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 40e5db4aabcd32834ee524857b77d36921f6bdfe) --- testprogs/blackbox/dbcheck.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testprogs/blackbox/dbcheck.sh b/testprogs/blackbox/dbcheck.sh index caf89ca402b..e2ba987e2de 100755 --- a/testprogs/blackbox/dbcheck.sh +++ b/testprogs/blackbox/dbcheck.sh @@ -19,7 +19,7 @@ dbcheck() { # This list of attributes can be freely extended dbcheck_fix_one_way_links() { - $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes fix_all_old_dn_string_component_mismatch --attrs="lastKnownParent defaultObjectCategory fromServer rIDSetReferences" --cross-ncs $ARGS + $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes fix_all_old_dn_string_component_mismatch --attrs="lastKnownParent defaultObjectCategory fromServer rIDSetReferences msDS-RevealOnDemandGroup msDS-NeverRevealGroup" --cross-ncs $ARGS } # This list of attributes can be freely extended -- 2.25.1 From a3977b4e784cc00f5f3db35836011300c4224936 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 14 Oct 2021 16:58:15 +1300 Subject: [PATCH 113/162] tests/krb5: Add TKT_SIG_SUPPORT environment variable This lets us indicate that service tickets should be issued with ticket checksums in the PAC. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett [abartlet@samba.org backported from commit ae2c57fb0332f94ac44d0886c5edbed707ef52fe due to changes in other tests nearby in tests.py] --- python/samba/tests/krb5/raw_testcase.py | 6 ++++ source4/selftest/tests.py | 41 +++++++++++++++++-------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 188a54451d3..1f7c51c07a5 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -574,6 +574,12 @@ class RawKerberosTest(TestCaseInTempDir): kdc_fast_support = '0' cls.kdc_fast_support = bool(int(kdc_fast_support)) + tkt_sig_support = samba.tests.env_get_var_value('TKT_SIG_SUPPORT', + allow_missing=True) + if tkt_sig_support is None: + tkt_sig_support = '0' + cls.tkt_sig_support = bool(int(tkt_sig_support)) + def setUp(self): super().setUp() self.do_asn1_print = False diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index ae8da7c8e34..4432ce2fbdc 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -788,46 +788,54 @@ planoldpythontestsuite("ad_dc:local", "samba.tests.gpo", extra_args=['-U"$USERNA planoldpythontestsuite("ad_dc:local", "samba.tests.dckeytab", extra_args=['-U"$USERNAME%$PASSWORD"']) have_fast_support = int('SAMBA_USES_MITKDC' in config_hash) +tkt_sig_support = 0 planoldpythontestsuite("none", "samba.tests.krb5.kcrypto") planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.simple_tests", environ={'SERVICE_USERNAME':'$SERVER', - 'FAST_SUPPORT': have_fast_support}) + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support}) planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests", environ={'SERVICE_USERNAME':'srv_account', 'SERVICE_PASSWORD':'$PASSWORD', 'FOR_USER':'$USERNAME', - 'FAST_SUPPORT': have_fast_support}) + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support}) planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests", - environ={'FAST_SUPPORT': have_fast_support}) + environ={'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support}) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ccache", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_rpc", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) for env in ["ad_dc", smbv1_disabled_testenv]: @@ -1376,7 +1384,8 @@ for env in ["fl2008r2dc", "fl2003dc"]: 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) @@ -1398,7 +1407,8 @@ planpythontestsuite("ad_dc", "samba.tests.krb5.as_canonicalization_tests", environ={ 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests", environ={ @@ -1406,9 +1416,11 @@ planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests", 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests", - environ={'FAST_SUPPORT': have_fast_support}) + environ={'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support}) planpythontestsuite( "ad_dc", "samba.tests.krb5.kdc_tgs_tests", @@ -1416,7 +1428,8 @@ planpythontestsuite( 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) planpythontestsuite( "ad_dc", @@ -1425,7 +1438,8 @@ planpythontestsuite( 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) planpythontestsuite( "ad_dc", @@ -1434,7 +1448,8 @@ planpythontestsuite( 'ADMIN_USERNAME': '$USERNAME', 'ADMIN_PASSWORD': '$PASSWORD', 'STRICT_CHECKING': '0', - 'FAST_SUPPORT': have_fast_support + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support }) for env in [ -- 2.25.1 From 02852a10be1d9075fd0c86c36aa8616d06c65883 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 5 Oct 2021 15:39:11 +1300 Subject: [PATCH 114/162] tests/krb5: Require ticket checksums if decryption key is available We perform this check conditionally, because MIT doesn't currently add ticket checksums. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit bf63221722903665e7b20991021fb5cdf4e4327e) --- python/samba/tests/krb5/raw_testcase.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 1f7c51c07a5..2e289c90ce7 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2493,15 +2493,14 @@ class RawKerberosTest(TestCaseInTempDir): ticket_private=ticket_private, encpart_private=encpart_private) - # TODO: This parameter should be removed when all service tickets are - # issued with ticket checksums. expect_ticket_checksum = kdc_exchange_dict['expect_ticket_checksum'] if expect_ticket_checksum: self.assertIsNotNone(ticket_decryption_key) if ticket_decryption_key is not None: self.verify_ticket(ticket_creds, krbtgt_key, expect_pac=expect_pac, - expect_ticket_checksum=expect_ticket_checksum) + expect_ticket_checksum=expect_ticket_checksum + or self.tkt_sig_support) kdc_exchange_dict['rep_ticket_creds'] = ticket_creds -- 2.25.1 From ea284630a167f027e3ed90ead2d15e7ee26dbb83 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 6 Oct 2021 16:35:47 +1300 Subject: [PATCH 115/162] tests/krb5: Verify tickets obtained with get_service_ticket() We only require the ticket checksum with Heimdal, because MIT currently doesn't add it. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit d86eee2fd0fb72e52d878ceba0c476ca58abe6cf) --- python/samba/tests/krb5/kdc_base_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 93951586cc7..8a5e12bbed4 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1287,6 +1287,14 @@ class KDCBaseTest(RawKerberosTest): sname=sname, decryption_key=target_key) + if to_rodc: + krbtgt_creds = self.get_rodc_krbtgt_creds() + else: + krbtgt_creds = self.get_krbtgt_creds() + krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + self.verify_ticket(service_ticket_creds, krbtgt_key, + expect_ticket_checksum=self.tkt_sig_support) + self.tkt_cache[cache_key] = service_ticket_creds return service_ticket_creds -- 2.25.1 From aef477136f4407c42e741e5d85f7b25ccaa30405 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 30 Sep 2021 15:03:04 +1300 Subject: [PATCH 116/162] tests/krb5: Add constrained delegation tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 56ccdba54e0c7cf3409d8430ea1012e5d3d9b092) --- python/samba/tests/krb5/rfc4120_constants.py | 5 + python/samba/tests/krb5/rodc_tests.py | 73 ++ python/samba/tests/krb5/s4u_tests.py | 958 ++++++++++++++++++- python/samba/tests/usage.py | 1 + selftest/knownfail_heimdal_kdc | 29 + source4/selftest/tests.py | 11 +- 6 files changed, 1070 insertions(+), 7 deletions(-) create mode 100755 python/samba/tests/krb5/rodc_tests.py diff --git a/python/samba/tests/krb5/rfc4120_constants.py b/python/samba/tests/krb5/rfc4120_constants.py index 76f2b75d94e..39bb2db8e32 100644 --- a/python/samba/tests/krb5/rfc4120_constants.py +++ b/python/samba/tests/krb5/rfc4120_constants.py @@ -69,12 +69,17 @@ PADATA_SUPPORTED_ETYPES = int( KDC_ERR_C_PRINCIPAL_UNKNOWN = 6 KDC_ERR_S_PRINCIPAL_UNKNOWN = 7 KDC_ERR_POLICY = 12 +KDC_ERR_BADOPTION = 13 KDC_ERR_ETYPE_NOSUPP = 14 +KDC_ERR_SUMTYPE_NOSUPP = 15 KDC_ERR_PREAUTH_FAILED = 24 KDC_ERR_PREAUTH_REQUIRED = 25 +KDC_ERR_BAD_INTEGRITY = 31 KDC_ERR_NOT_US = 35 KDC_ERR_BADMATCH = 36 KDC_ERR_SKEW = 37 +KDC_ERR_MODIFIED = 41 +KDC_ERR_INAPP_CKSUM = 50 KDC_ERR_GENERIC = 60 KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS = 93 diff --git a/python/samba/tests/krb5/rodc_tests.py b/python/samba/tests/krb5/rodc_tests.py new file mode 100755 index 00000000000..4579f9eb552 --- /dev/null +++ b/python/samba/tests/krb5/rodc_tests.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# Unix SMB/CIFS implementation. +# Copyright (C) Stefan Metzmacher 2020 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import sys +import os + +from samba.tests.krb5.kdc_base_test import KDCBaseTest + +sys.path.insert(0, "bin/python") +os.environ["PYTHONUNBUFFERED"] = "1" + +global_asn1_print = False +global_hexdump = False + + +class RodcKerberosTests(KDCBaseTest): + + def setUp(self): + super().setUp() + self.do_asn1_print = global_asn1_print + self.do_hexdump = global_hexdump + + # Ensure that an RODC correctly issues tickets signed with its krbtgt key + # and including the RODCIdentifier. + def test_rodc_ticket_signature(self): + user_creds = self.get_cached_creds( + machine_account=False, + opts={ + 'revealed_to_rodc': True + }) + target_creds = self.get_cached_creds( + machine_account=True, + opts={ + 'revealed_to_rodc': True + }) + + krbtgt_creds = self.get_rodc_krbtgt_creds() + rodc_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + + # Get a TGT from the RODC. + tgt = self.get_tgt(user_creds, to_rodc=True) + + # Ensure the PAC contains the expected checksums. + self.verify_ticket(tgt, rodc_key) + + # Get a service ticket from the RODC. + service_ticket = self.get_service_ticket(tgt, target_creds, + to_rodc=True) + + # Ensure the PAC contains the expected checksums. + self.verify_ticket(service_ticket, rodc_key) + + +if __name__ == "__main__": + global_asn1_print = False + global_hexdump = False + import unittest + unittest.main() diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py index bbddef4d6e0..9a25256081a 100755 --- a/python/samba/tests/krb5/s4u_tests.py +++ b/python/samba/tests/krb5/s4u_tests.py @@ -18,17 +18,34 @@ import sys import os +import functools sys.path.insert(0, "bin/python") os.environ["PYTHONUNBUFFERED"] = "1" +from samba import ntstatus +from samba.dcerpc import krb5pac, lsa + from samba.tests import env_get_var_value -from samba.tests.krb5.kcrypto import Cksumtype -from samba.tests.krb5.raw_testcase import RawKerberosTest +from samba.tests.krb5.kcrypto import Cksumtype, Enctype +from samba.tests.krb5.kdc_base_test import KDCBaseTest +from samba.tests.krb5.raw_testcase import ( + RodcPacEncryptionKey, + ZeroedChecksumKey +) from samba.tests.krb5.rfc4120_constants import ( + AES256_CTS_HMAC_SHA1_96, + ARCFOUR_HMAC_MD5, + KDC_ERR_BADOPTION, + KDC_ERR_BAD_INTEGRITY, + KDC_ERR_GENERIC, + KDC_ERR_INAPP_CKSUM, + KDC_ERR_MODIFIED, + KDC_ERR_SUMTYPE_NOSUPP, KU_PA_ENC_TIMESTAMP, KU_AS_REP_ENC_PART, KU_TGS_REP_ENC_PART_SUB_KEY, + NT_PRINCIPAL ) import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1 @@ -36,7 +53,7 @@ global_asn1_print = False global_hexdump = False -class S4UKerberosTests(RawKerberosTest): +class S4UKerberosTests(KDCBaseTest): def setUp(self): super(S4UKerberosTests, self).setUp() @@ -119,8 +136,14 @@ class S4UKerberosTests(RawKerberosTest): self.assertEqual(msg_type, 11) enc_part2 = key.decrypt(KU_AS_REP_ENC_PART, rep['enc-part']['cipher']) - enc_part2 = self.der_decode( - enc_part2, asn1Spec=krb5_asn1.EncASRepPart()) + # MIT KDC encodes both EncASRepPart and EncTGSRepPart with + # application tag 26 + try: + enc_part2 = self.der_decode( + enc_part2, asn1Spec=krb5_asn1.EncASRepPart()) + except Exception: + enc_part2 = self.der_decode( + enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart()) # S4U2Self Request sname = cname @@ -195,6 +218,931 @@ class S4UKerberosTests(RawKerberosTest): msg_type = self._test_s4u2self(pa_s4u2self_ctype=Cksumtype.CRC32) self.assertEqual(msg_type, 30) + def _run_s4u2self_test(self, kdc_dict): + client_opts = kdc_dict.pop('client_opts', None) + client_creds = self.get_cached_creds(machine_account=False, + opts=client_opts) + + service_opts = kdc_dict.pop('service_opts', None) + service_creds = self.get_cached_creds(machine_account=True, + opts=service_opts) + + service_tgt = self.get_tgt(service_creds) + modify_service_tgt_fn = kdc_dict.pop('modify_service_tgt_fn', None) + if modify_service_tgt_fn is not None: + service_tgt = modify_service_tgt_fn(service_tgt) + + client_name = client_creds.get_username() + client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=[client_name]) + + service_name = service_creds.get_username()[:-1] + service_sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=['host', service_name]) + + realm = client_creds.get_realm() + + expected_flags = kdc_dict.pop('expected_flags', None) + if expected_flags is not None: + expected_flags = krb5_asn1.TicketFlags(expected_flags) + + unexpected_flags = kdc_dict.pop('unexpected_flags', None) + if unexpected_flags is not None: + unexpected_flags = krb5_asn1.TicketFlags(unexpected_flags) + + kdc_options = kdc_dict.pop('kdc_options', '0') + kdc_options = krb5_asn1.KDCOptions(kdc_options) + + service_decryption_key = self.TicketDecryptionKey_from_creds( + service_creds) + + authenticator_subkey = self.RandomKey(Enctype.AES256) + + etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96, + ARCFOUR_HMAC_MD5)) + + def generate_s4u2self_padata(_kdc_exchange_dict, + _callback_dict, + req_body): + pa_s4u = self.PA_S4U2Self_create( + name=client_cname, + realm=realm, + tgt_session_key=service_tgt.session_key, + ctype=None) + + return [pa_s4u], req_body + + kdc_exchange_dict = self.tgs_exchange_dict( + expected_crealm=realm, + expected_cname=client_cname, + expected_srealm=realm, + expected_sname=service_sname, + expected_flags=expected_flags, + unexpected_flags=unexpected_flags, + ticket_decryption_key=service_decryption_key, + expect_ticket_checksum=True, + generate_padata_fn=generate_s4u2self_padata, + check_rep_fn=self.generic_check_kdc_rep, + check_kdc_private_fn=self.generic_check_kdc_private, + expected_error_mode=0, + tgt=service_tgt, + authenticator_subkey=authenticator_subkey, + kdc_options=str(kdc_options), + expect_claims=False) + + self._generic_kdc_exchange(kdc_exchange_dict, + cname=None, + realm=realm, + sname=service_sname, + etypes=etypes) + + # Ensure we used all the parameters given to us. + self.assertEqual({}, kdc_dict) + + # Test performing an S4U2Self operation with a forwardable ticket. The + # resulting ticket should have the 'forwardable' flag set. + def test_s4u2self_forwardable(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': False + }, + 'kdc_options': 'forwardable', + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=True), + 'expected_flags': 'forwardable' + }) + + # Test performing an S4U2Self operation without requesting a forwardable + # ticket. The resulting ticket should not have the 'forwardable' flag set. + def test_s4u2self_without_forwardable(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': False + }, + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=True), + 'unexpected_flags': 'forwardable' + }) + + # Do an S4U2Self with a non-forwardable TGT. The 'forwardable' flag should + # not be set on the ticket. + def test_s4u2self_not_forwardable(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': False + }, + 'kdc_options': 'forwardable', + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=False), + 'unexpected_flags': 'forwardable' + }) + + # Do an S4U2Self with the not_delegated flag set on the client. The + # 'forwardable' flag should not be set on the ticket. + def test_s4u2self_client_not_delegated(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': True + }, + 'kdc_options': 'forwardable', + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=True), + 'unexpected_flags': 'forwardable' + }) + + # Do an S4U2Self with a service not trusted to authenticate for delegation, + # but having an empty msDS-AllowedToDelegateTo attribute. The 'forwardable' + # flag should be set on the ticket. + def test_s4u2self_not_trusted_empty_allowed(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': False + }, + 'service_opts': { + 'trusted_to_auth_for_delegation': False, + 'delegation_to_spn': () + }, + 'kdc_options': 'forwardable', + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=True), + 'expected_flags': 'forwardable' + }) + + # Do an S4U2Self with a service not trusted to authenticate for delegation + # and having a non-empty msDS-AllowedToDelegateTo attribute. The + # 'forwardable' flag should not be set on the ticket. + def test_s4u2self_not_trusted_nonempty_allowed(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': False + }, + 'service_opts': { + 'trusted_to_auth_for_delegation': False, + 'delegation_to_spn': ('test',) + }, + 'kdc_options': 'forwardable', + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=True), + 'unexpected_flags': 'forwardable' + }) + + # Do an S4U2Self with a service trusted to authenticate for delegation and + # having an empty msDS-AllowedToDelegateTo attribute. The 'forwardable' + # flag should be set on the ticket. + def test_s4u2self_trusted_empty_allowed(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': False + }, + 'service_opts': { + 'trusted_to_auth_for_delegation': True, + 'delegation_to_spn': () + }, + 'kdc_options': 'forwardable', + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=True), + 'expected_flags': 'forwardable' + }) + + # Do an S4U2Self with a service trusted to authenticate for delegation and + # having a non-empty msDS-AllowedToDelegateTo attribute. The 'forwardable' + # flag should be set on the ticket. + def test_s4u2self_trusted_nonempty_allowed(self): + self._run_s4u2self_test( + { + 'client_opts': { + 'not_delegated': False + }, + 'service_opts': { + 'trusted_to_auth_for_delegation': True, + 'delegation_to_spn': ('test',) + }, + 'kdc_options': 'forwardable', + 'modify_service_tgt_fn': functools.partial( + self.set_ticket_forwardable, flag=True), + 'expected_flags': 'forwardable' + }) + + def _run_delegation_test(self, kdc_dict): + client_opts = kdc_dict.pop('client_opts', None) + client_creds = self.get_cached_creds(machine_account=False, + opts=client_opts) + + service1_opts = kdc_dict.pop('service1_opts', {}) + service2_opts = kdc_dict.pop('service2_opts', {}) + + allow_delegation = kdc_dict.pop('allow_delegation', False) + allow_rbcd = kdc_dict.pop('allow_rbcd', False) + self.assertFalse(allow_delegation and allow_rbcd) + + if allow_rbcd: + service1_creds = self.get_cached_creds(machine_account=True, + opts=service1_opts) + + self.assertNotIn('delegation_from_dn', service2_opts) + service2_opts['delegation_from_dn'] = str(service1_creds.get_dn()) + + service2_creds = self.get_cached_creds(machine_account=True, + opts=service2_opts) + else: + service2_creds = self.get_cached_creds(machine_account=True, + opts=service2_opts) + + if allow_delegation: + self.assertNotIn('delegation_to_spn', service1_opts) + service1_opts['delegation_to_spn'] = service2_creds.get_spn() + + service1_creds = self.get_cached_creds(machine_account=True, + opts=service1_opts) + + client_tkt_options = kdc_dict.pop('client_tkt_options', 'forwardable') + expected_flags = krb5_asn1.TicketFlags(client_tkt_options) + + client_tgt = self.get_tgt(client_creds, + kdc_options=client_tkt_options, + expected_flags=expected_flags) + client_service_tkt = self.get_service_ticket( + client_tgt, + service1_creds, + kdc_options=client_tkt_options, + expected_flags=expected_flags) + + service1_tgt = self.get_tgt(service1_creds) + + modify_client_tkt_fn = kdc_dict.pop('modify_client_tkt_fn', None) + if modify_client_tkt_fn is not None: + client_service_tkt = modify_client_tkt_fn(client_service_tkt) + + additional_tickets = [client_service_tkt.ticket] + + modify_service_tgt_fn = kdc_dict.pop('modify_service_tgt_fn', None) + if modify_service_tgt_fn is not None: + service1_tgt = modify_service_tgt_fn(service1_tgt) + + kdc_options = kdc_dict.pop('kdc_options', None) + if kdc_options is None: + kdc_options = str(krb5_asn1.KDCOptions('cname-in-addl-tkt')) + + client_username = client_creds.get_username() + client_realm = client_creds.get_realm() + client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=[client_username]) + + service1_name = service1_creds.get_username()[:-1] + service1_realm = service1_creds.get_realm() + + service2_name = service2_creds.get_username()[:-1] + service2_realm = service2_creds.get_realm() + service2_service = 'host' + service2_sname = self.PrincipalName_create( + name_type=NT_PRINCIPAL, names=[service2_service, + service2_name]) + service2_decryption_key = self.TicketDecryptionKey_from_creds( + service2_creds) + service2_etypes = service2_creds.tgs_supported_enctypes + + expected_error_mode = kdc_dict.pop('expected_error_mode') + expected_status = kdc_dict.pop('expected_status', None) + if expected_error_mode: + check_error_fn = self.generic_check_kdc_error + check_rep_fn = None + else: + check_error_fn = None + check_rep_fn = self.generic_check_kdc_rep + + self.assertIsNone(expected_status) + + expect_edata = kdc_dict.pop('expect_edata', None) + if expect_edata is not None: + self.assertTrue(expected_error_mode) + + pac_options = kdc_dict.pop('pac_options', None) + + authenticator_subkey = self.RandomKey(Enctype.AES256) + + etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96, + ARCFOUR_HMAC_MD5)) + + expected_proxy_target = service2_creds.get_spn() + + expected_transited_services = kdc_dict.pop( + 'expected_transited_services', []) + + transited_service = f'host/{service1_name}@{service1_realm}' + expected_transited_services.append(transited_service) + + kdc_exchange_dict = self.tgs_exchange_dict( + expected_crealm=client_realm, + expected_cname=client_cname, + expected_srealm=service2_realm, + expected_sname=service2_sname, + expected_supported_etypes=service2_etypes, + ticket_decryption_key=service2_decryption_key, + check_error_fn=check_error_fn, + check_rep_fn=check_rep_fn, + check_kdc_private_fn=self.generic_check_kdc_private, + expected_error_mode=expected_error_mode, + expected_status=expected_status, + callback_dict={}, + tgt=service1_tgt, + authenticator_subkey=authenticator_subkey, + kdc_options=kdc_options, + pac_options=pac_options, + expect_edata=expect_edata, + expected_proxy_target=expected_proxy_target, + expected_transited_services=expected_transited_services) + + self._generic_kdc_exchange(kdc_exchange_dict, + cname=None, + realm=service2_realm, + sname=service2_sname, + etypes=etypes, + additional_tickets=additional_tickets) + + # Ensure we used all the parameters given to us. + self.assertEqual({}, kdc_dict) + + def test_constrained_delegation(self): + # Test constrained delegation. + self._run_delegation_test( + { + 'expected_error_mode': 0, + 'allow_delegation': True + }) + + def test_constrained_delegation_existing_delegation_info(self): + # Test constrained delegation with an existing S4U_DELEGATION_INFO + # structure in the PAC. + + services = ['service1', 'service2', 'service3'] + + self._run_delegation_test( + { + 'expected_error_mode': 0, + 'allow_delegation': True, + 'modify_client_tkt_fn': functools.partial( + self.add_delegation_info, services=services), + 'expected_transited_services': services + }) + + def test_constrained_delegation_not_allowed(self): + # Test constrained delegation when the delegating service does not + # allow it. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_delegation': False + }) + + def test_constrained_delegation_no_client_pac(self): + # Test constrained delegation when the client service ticket does not + # contain a PAC. + self._run_delegation_test( + { + 'expected_error_mode': (KDC_ERR_BADOPTION, + KDC_ERR_MODIFIED), + 'allow_delegation': True, + 'modify_client_tkt_fn': self.remove_ticket_pac, + 'expect_edata': False + }) + + def test_constrained_delegation_no_service_pac(self): + # Test constrained delegation when the service TGT does not contain a + # PAC. + self._run_delegation_test( + { + 'expected_error_mode': 0, + 'allow_delegation': True, + 'modify_service_tgt_fn': self.remove_ticket_pac + }) + + def test_constrained_delegation_non_forwardable(self): + # Test constrained delegation with a non-forwardable ticket. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': ntstatus.NT_STATUS_ACCOUNT_RESTRICTION, + 'allow_delegation': True, + 'modify_client_tkt_fn': functools.partial( + self.set_ticket_forwardable, flag=False) + }) + + def test_constrained_delegation_pac_options_rbcd(self): + # Test constrained delegation, but with the RBCD bit set in the PAC + # options. + self._run_delegation_test( + { + 'expected_error_mode': 0, + 'pac_options': '0001', # supports RBCD + 'allow_delegation': True + }) + + def test_rbcd_existing_delegation_info(self): + # Test constrained delegation with an existing S4U_DELEGATION_INFO + # structure in the PAC. + + services = ['service1', 'service2', 'service3'] + + self._run_delegation_test( + { + 'expected_error_mode': 0, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': functools.partial( + self.add_delegation_info, services=services), + 'expected_transited_services': services + }) + + def test_rbcd_not_allowed(self): + # Test resource-based constrained delegation when the target service + # does not allow it. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': ntstatus.NT_STATUS_NOT_FOUND, + 'allow_rbcd': False, + 'pac_options': '0001' # supports RBCD + }) + + def test_rbcd_no_client_pac_a(self): + # Test constrained delegation when the client service ticket does not + # contain a PAC, and an empty msDS-AllowedToDelegateTo attribute. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_MODIFIED, + 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': self.remove_ticket_pac + }) + + def test_rbcd_no_client_pac_b(self): + # Test constrained delegation when the client service ticket does not + # contain a PAC, and a non-empty msDS-AllowedToDelegateTo attribute. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_MODIFIED, + 'expected_status': ntstatus.NT_STATUS_NO_MATCH, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': self.remove_ticket_pac, + 'service1_opts': { + 'delegation_to_spn': ('host/test') + } + }) + + def test_rbcd_no_service_pac(self): + # Test constrained delegation when the service TGT does not contain a + # PAC. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': + ntstatus.NT_STATUS_NOT_FOUND, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_service_tgt_fn': self.remove_ticket_pac + }) + + def test_rbcd_non_forwardable(self): + # Test resource-based constrained delegation with a non-forwardable + # ticket. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': ntstatus.NT_STATUS_ACCOUNT_RESTRICTION, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': functools.partial( + self.set_ticket_forwardable, flag=False) + }) + + def test_rbcd_no_pac_options_a(self): + # Test resource-based constrained delegation without the RBCD bit set + # in the PAC options, and an empty msDS-AllowedToDelegateTo attribute. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_rbcd': True, + 'pac_options': '1' # does not support RBCD + }) + + def test_rbcd_no_pac_options_b(self): + # Test resource-based constrained delegation without the RBCD bit set + # in the PAC options, and a non-empty msDS-AllowedToDelegateTo + # attribute. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': ntstatus.NT_STATUS_NO_MATCH, + 'allow_rbcd': True, + 'pac_options': '1', # does not support RBCD + 'service1_opts': { + 'delegation_to_spn': ('host/test') + } + }) + + def test_bronze_bit_constrained_delegation_old_checksum(self): + # Attempt to modify the ticket without updating the PAC checksums. + self._run_delegation_test( + { + 'expected_error_mode': (KDC_ERR_MODIFIED, + KDC_ERR_BAD_INTEGRITY), + 'allow_delegation': True, + 'client_tkt_options': '0', # non-forwardable ticket + 'modify_client_tkt_fn': functools.partial( + self.set_ticket_forwardable, + flag=True, update_pac_checksums=False), + 'expect_edata': False + }) + + def test_bronze_bit_rbcd_old_checksum(self): + # Attempt to modify the ticket without updating the PAC checksums. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_MODIFIED, + 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'client_tkt_options': '0', # non-forwardable ticket + 'modify_client_tkt_fn': functools.partial( + self.set_ticket_forwardable, + flag=True, update_pac_checksums=False) + }) + + def test_constrained_delegation_missing_client_checksum(self): + # Present a user ticket without the required checksums. + for checksum in self.pac_checksum_types: + with self.subTest(checksum=checksum): + if checksum == krb5pac.PAC_TYPE_TICKET_CHECKSUM: + expected_error_mode = (KDC_ERR_BADOPTION, + KDC_ERR_MODIFIED) + else: + expected_error_mode = KDC_ERR_GENERIC + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'allow_delegation': True, + 'modify_client_tkt_fn': functools.partial( + self.remove_pac_checksum, checksum=checksum), + 'expect_edata': False + }) + + def test_constrained_delegation_missing_service_checksum(self): + # Present the service's ticket without the required checksums. + for checksum in filter(lambda x: x != krb5pac.PAC_TYPE_TICKET_CHECKSUM, + self.pac_checksum_types): + with self.subTest(checksum=checksum): + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_GENERIC, + 'expected_status': + ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES, + 'allow_delegation': True, + 'modify_service_tgt_fn': functools.partial( + self.remove_pac_checksum, checksum=checksum) + }) + + def test_rbcd_missing_client_checksum(self): + # Present a user ticket without the required checksums. + for checksum in self.pac_checksum_types: + with self.subTest(checksum=checksum): + if checksum == krb5pac.PAC_TYPE_TICKET_CHECKSUM: + expected_error_mode = KDC_ERR_MODIFIED + else: + expected_error_mode = KDC_ERR_GENERIC + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'expected_status': + ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': functools.partial( + self.remove_pac_checksum, checksum=checksum) + }) + + def test_rbcd_missing_service_checksum(self): + # Present the service's ticket without the required checksums. + for checksum in filter(lambda x: x != krb5pac.PAC_TYPE_TICKET_CHECKSUM, + self.pac_checksum_types): + with self.subTest(checksum=checksum): + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_GENERIC, + 'expected_status': + ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_service_tgt_fn': functools.partial( + self.remove_pac_checksum, checksum=checksum) + }) + + def test_constrained_delegation_zeroed_client_checksum(self): + # Present a user ticket with invalid checksums. + for checksum in self.pac_checksum_types: + with self.subTest(checksum=checksum): + self._run_delegation_test( + { + 'expected_error_mode': (KDC_ERR_MODIFIED, + KDC_ERR_BAD_INTEGRITY), + 'allow_delegation': True, + 'modify_client_tkt_fn': functools.partial( + self.zeroed_pac_checksum, checksum=checksum), + 'expect_edata': False + }) + + def test_constrained_delegation_zeroed_service_checksum(self): + # Present the service's ticket with invalid checksums. + for checksum in self.pac_checksum_types: + with self.subTest(checksum=checksum): + if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM: + expected_error_mode = (KDC_ERR_MODIFIED, + KDC_ERR_BAD_INTEGRITY) + expected_status = ntstatus.NT_STATUS_WRONG_PASSWORD + else: + expected_error_mode = 0 + expected_status = None + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'expected_status': expected_status, + 'allow_delegation': True, + 'modify_service_tgt_fn': functools.partial( + self.zeroed_pac_checksum, checksum=checksum) + }) + + def test_rbcd_zeroed_client_checksum(self): + # Present a user ticket with invalid checksums. + for checksum in self.pac_checksum_types: + with self.subTest(checksum=checksum): + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_MODIFIED, + 'expected_status': + ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': functools.partial( + self.zeroed_pac_checksum, checksum=checksum) + }) + + def test_rbcd_zeroed_service_checksum(self): + # Present the service's ticket with invalid checksums. + for checksum in self.pac_checksum_types: + with self.subTest(checksum=checksum): + if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM: + expected_error_mode = (KDC_ERR_MODIFIED, + KDC_ERR_BAD_INTEGRITY) + expected_status = ntstatus.NT_STATUS_WRONG_PASSWORD + else: + expected_error_mode = 0 + expected_status = None + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'expected_status': expected_status, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_service_tgt_fn': functools.partial( + self.zeroed_pac_checksum, checksum=checksum) + }) + + unkeyed_ctypes = {Cksumtype.MD5, Cksumtype.SHA1, Cksumtype.CRC32} + + def test_constrained_delegation_unkeyed_client_checksum(self): + # Present a user ticket with invalid checksums. + for checksum in self.pac_checksum_types: + for ctype in self.unkeyed_ctypes: + with self.subTest(checksum=checksum, ctype=ctype): + if (checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM + and ctype == Cksumtype.SHA1): + expected_error_mode = (KDC_ERR_SUMTYPE_NOSUPP, + KDC_ERR_INAPP_CKSUM) + else: + expected_error_mode = (KDC_ERR_GENERIC, + KDC_ERR_INAPP_CKSUM) + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'allow_delegation': True, + 'modify_client_tkt_fn': functools.partial( + self.unkeyed_pac_checksum, + checksum=checksum, ctype=ctype), + 'expect_edata': False + }) + + def test_constrained_delegation_unkeyed_service_checksum(self): + # Present the service's ticket with invalid checksums. + for checksum in self.pac_checksum_types: + for ctype in self.unkeyed_ctypes: + with self.subTest(checksum=checksum, ctype=ctype): + if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM: + if ctype == Cksumtype.SHA1: + expected_error_mode = (KDC_ERR_SUMTYPE_NOSUPP, + KDC_ERR_INAPP_CKSUM) + expected_status = ntstatus.NT_STATUS_LOGON_FAILURE + else: + expected_error_mode = (KDC_ERR_GENERIC, + KDC_ERR_INAPP_CKSUM) + expected_status = ( + ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES) + else: + expected_error_mode = 0 + expected_status = None + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'expected_status': expected_status, + 'allow_delegation': True, + 'modify_service_tgt_fn': functools.partial( + self.unkeyed_pac_checksum, + checksum=checksum, ctype=ctype) + }) + + def test_rbcd_unkeyed_client_checksum(self): + # Present a user ticket with invalid checksums. + for checksum in self.pac_checksum_types: + for ctype in self.unkeyed_ctypes: + with self.subTest(checksum=checksum, ctype=ctype): + if (checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM + and ctype == Cksumtype.SHA1): + expected_error_mode = KDC_ERR_SUMTYPE_NOSUPP + else: + expected_error_mode = KDC_ERR_GENERIC + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'expected_status': + ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': functools.partial( + self.unkeyed_pac_checksum, + checksum=checksum, ctype=ctype) + }) + + def test_rbcd_unkeyed_service_checksum(self): + # Present the service's ticket with invalid checksums. + for checksum in self.pac_checksum_types: + for ctype in self.unkeyed_ctypes: + with self.subTest(checksum=checksum, ctype=ctype): + if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM: + if ctype == Cksumtype.SHA1: + expected_error_mode = (KDC_ERR_SUMTYPE_NOSUPP, + KDC_ERR_BAD_INTEGRITY) + expected_status = ntstatus.NT_STATUS_LOGON_FAILURE + else: + expected_error_mode = KDC_ERR_GENERIC + expected_status = ( + ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES) + else: + expected_error_mode = 0 + expected_status = None + + self._run_delegation_test( + { + 'expected_error_mode': expected_error_mode, + 'expected_status': expected_status, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_service_tgt_fn': functools.partial( + self.unkeyed_pac_checksum, + checksum=checksum, ctype=ctype) + }) + + def remove_pac_checksum(self, ticket, checksum): + checksum_keys = self.get_krbtgt_checksum_key() + + return self.modified_ticket(ticket, + checksum_keys=checksum_keys, + include_checksums={checksum: False}) + + def zeroed_pac_checksum(self, ticket, checksum): + krbtgt_creds = self.get_krbtgt_creds() + krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + + server_key = ticket.decryption_key + + checksum_keys = { + krb5pac.PAC_TYPE_SRV_CHECKSUM: server_key, + krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key, + krb5pac.PAC_TYPE_TICKET_CHECKSUM: krbtgt_key, + } + + if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM: + zeroed_key = server_key + else: + zeroed_key = krbtgt_key + + checksum_keys[checksum] = ZeroedChecksumKey(zeroed_key.key, + zeroed_key.kvno) + + return self.modified_ticket(ticket, + checksum_keys=checksum_keys, + include_checksums={checksum: True}) + + def unkeyed_pac_checksum(self, ticket, checksum, ctype): + krbtgt_creds = self.get_krbtgt_creds() + krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) + + server_key = ticket.decryption_key + + checksum_keys = { + krb5pac.PAC_TYPE_SRV_CHECKSUM: server_key, + krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key, + krb5pac.PAC_TYPE_TICKET_CHECKSUM: krbtgt_key, + } + + # Make a copy of the existing key and change the ctype. + key = checksum_keys[checksum] + new_key = RodcPacEncryptionKey(key.key, key.kvno) + new_key.ctype = ctype + checksum_keys[checksum] = new_key + + return self.modified_ticket(ticket, + checksum_keys=checksum_keys, + include_checksums={checksum: True}) + + def add_delegation_info(self, ticket, services=None): + def modify_pac_fn(pac): + pac_buffers = pac.buffers + self.assertNotIn(krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION, + (buffer.type for buffer in pac_buffers)) + + transited_services = list(map(lsa.String, services)) + + delegation = krb5pac.PAC_CONSTRAINED_DELEGATION() + delegation.proxy_target = lsa.String('test_proxy_target') + delegation.transited_services = transited_services + delegation.num_transited_services = len(transited_services) + + info = krb5pac.PAC_CONSTRAINED_DELEGATION_CTR() + info.info = delegation + + pac_buffer = krb5pac.PAC_BUFFER() + pac_buffer.type = krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION + pac_buffer.info = info + + pac_buffers.append(pac_buffer) + + pac.buffers = pac_buffers + pac.num_buffers += 1 + + return pac + + checksum_keys = self.get_krbtgt_checksum_key() + + return self.modified_ticket(ticket, + checksum_keys=checksum_keys, + modify_pac_fn=modify_pac_fn) + + def set_ticket_forwardable(self, ticket, flag, update_pac_checksums=True): + flag = '1' if flag else '0' + + def modify_fn(enc_part): + # Reset the forwardable flag + forwardable_pos = (len(tuple(krb5_asn1.TicketFlags('forwardable'))) + - 1) + + flags = enc_part['flags'] + self.assertLessEqual(forwardable_pos, len(flags)) + enc_part['flags'] = (flags[:forwardable_pos] + + flag + + flags[forwardable_pos+1:]) + + return enc_part + + if update_pac_checksums: + checksum_keys = self.get_krbtgt_checksum_key() + else: + checksum_keys = None + + return self.modified_ticket(ticket, + modify_fn=modify_fn, + checksum_keys=checksum_keys, + update_pac_checksums=update_pac_checksums) + + def remove_ticket_pac(self, ticket): + return self.modified_ticket(ticket, + exclude_pac=True) + if __name__ == "__main__": global_asn1_print = False diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py index 29990ec9511..e1711b532d7 100644 --- a/python/samba/tests/usage.py +++ b/python/samba/tests/usage.py @@ -102,6 +102,7 @@ EXCLUDE_USAGE = { 'python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py', 'python/samba/tests/krb5/as_req_tests.py', 'python/samba/tests/krb5/fast_tests.py', + 'python/samba/tests/krb5/rodc_tests.py', } EXCLUDE_HELP = { diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 6eb667f8969..0b8e83f1f3f 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -125,3 +125,32 @@ # Heimdal currently does not generate ticket signatures # ^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_heimdal_ticket_signature +# +# S4U tests +# +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_missing_client_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_client_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_service_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_zeroed_client_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_zeroed_service_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_existing_delegation_info +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_missing_client_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_a +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_b +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_unkeyed_client_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_unkeyed_service_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_client_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_service_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_client_not_delegated +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_forwardable +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_forwardable +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_empty_allowed +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_nonempty_allowed +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_trusted_empty_allowed +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_trusted_nonempty_allowed +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_without_forwardable +# +# RODC tests +# +^samba.tests.krb5.rodc_tests.samba.tests.krb5.rodc_tests.RodcKerberosTests.test_rodc_ticket_signature diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 4432ce2fbdc..187cdd18132 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -795,9 +795,16 @@ planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.simple_tests", 'FAST_SUPPORT': have_fast_support, 'TKT_SIG_SUPPORT': tkt_sig_support}) planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests", - environ={'SERVICE_USERNAME':'srv_account', - 'SERVICE_PASSWORD':'$PASSWORD', + environ={'ADMIN_USERNAME':'$USERNAME', + 'ADMIN_PASSWORD':'$PASSWORD', 'FOR_USER':'$USERNAME', + 'STRICT_CHECKING':'0', + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support}) +planoldpythontestsuite("rodc:local", "samba.tests.krb5.rodc_tests", + environ={'ADMIN_USERNAME':'$USERNAME', + 'ADMIN_PASSWORD':'$PASSWORD', + 'STRICT_CHECKING':'0', 'FAST_SUPPORT': have_fast_support, 'TKT_SIG_SUPPORT': tkt_sig_support}) -- 2.25.1 From 2ed907cd2af84e74981de9ef5acc4b23eff5cc2a Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 12:07:40 +1300 Subject: [PATCH 117/162] tests/krb5: Don't include empty AD-IF-RELEVANT BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 1a08399cd8169a525cc9e7aed99da84ef20e5b9c) --- python/samba/tests/krb5/raw_testcase.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 2e289c90ce7..e008223eb23 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -3424,14 +3424,19 @@ class RawKerberosTest(TestCaseInTempDir): if expect_pac: self.assertIsNotNone(old_pac, 'Expected PAC') - ad_relevant = self.der_encode( - relevant_elems, - asn1Spec=krb5_asn1.AD_IF_RELEVANT()) - - authdata_elem = self.AuthorizationData_create(AD_IF_RELEVANT, - ad_relevant) + if relevant_elems: + ad_relevant = self.der_encode( + relevant_elems, + asn1Spec=krb5_asn1.AD_IF_RELEVANT()) + + authdata_elem = self.AuthorizationData_create( + AD_IF_RELEVANT, + ad_relevant) + else: + authdata_elem = None - new_auth_data.append(authdata_elem) + if authdata_elem is not None: + new_auth_data.append(authdata_elem) if expect_pac: self.assertIsNotNone(ad_relevant, 'Expected AD-RELEVANT') -- 2.25.1 From 6860972c1660a8c2599440a05d43ff97d5dd76ec Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 15:41:35 +1300 Subject: [PATCH 118/162] tests/krb5: Allow bypassing cache when creating accounts BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 3948701f1d0f3ccd06f6dad56ca72833d66b1d84) --- python/samba/tests/krb5/kdc_base_test.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 8a5e12bbed4..87160f675ae 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -610,7 +610,8 @@ class KDCBaseTest(RawKerberosTest): def get_cached_creds(self, *, machine_account, - opts=None): + opts=None, + use_cache=True): if opts is None: opts = {} @@ -638,9 +639,13 @@ class KDCBaseTest(RawKerberosTest): cache_key = tuple(sorted(account_opts.items())) - creds = self.account_cache.get(cache_key) - if creds is None: - creds = self.create_account_opts(**account_opts) + if use_cache: + creds = self.account_cache.get(cache_key) + if creds is not None: + return creds + + creds = self.create_account_opts(**account_opts) + if use_cache: self.account_cache[cache_key] = creds return creds -- 2.25.1 From 800647adf0fad416291884de960a2f8e5a61a9a3 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 15:40:39 +1300 Subject: [PATCH 119/162] tests/krb5: Fix duplicate account creation BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 3dede18c5a1801023a60cc55b99022b033428350) --- .../krb5/ms_kile_client_principal_lookup_tests.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py index 501bc4892f4..2ee3d4a2a83 100755 --- a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py +++ b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py @@ -150,18 +150,15 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): # Create a machine account for the test. # samdb = self.get_samdb() - user_name = "mskilemac" - (mc, dn) = self.create_account(samdb, user_name, machine_account=True) - realm = mc.get_realm().lower() - mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, dn) = self.create_account(samdb, mach_name, machine_account=True) + realm = mc.get_realm().lower() # Do the initial AS-REQ, should get a pre-authentication required # response etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) cname = self.PrincipalName_create( - name_type=NT_PRINCIPAL, names=[user_name]) + name_type=NT_PRINCIPAL, names=[mach_name]) sname = self.PrincipalName_create( name_type=NT_SRV_INST, names=["krbtgt", realm]) @@ -180,7 +177,7 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): key = self.EncryptionKey_import(enc_part2['key']) cname = self.PrincipalName_create( name_type=NT_PRINCIPAL, - names=[user_name]) + names=[mach_name]) sname = self.PrincipalName_create( name_type=NT_PRINCIPAL, names=[mc.get_username()]) @@ -197,7 +194,7 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): # check the crealm and cname cname = enc_part['cname'] self.assertEqual(NT_PRINCIPAL, cname['name-type']) - self.assertEqual(user_name.encode('UTF8'), cname['name-string'][0]) + self.assertEqual(mach_name.encode('UTF8'), cname['name-string'][0]) self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm']) def test_nt_principal_step_3(self): -- 2.25.1 From 6fa37392eedf04f5aef42468025e5916d4347727 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 16:06:58 +1300 Subject: [PATCH 120/162] s4:kdc: Simplify samba_kdc_update_pac_blob() to take ldb_context as parameter BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 7149eeaceb426470b1b8181749d2d081c2fb83a4) --- source4/kdc/mit_samba.c | 7 +------ source4/kdc/pac-glue.c | 5 ++--- source4/kdc/pac-glue.h | 3 +-- source4/kdc/wdc-samba4.c | 2 +- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c index 54dcd545ea1..2936fe2d18a 100644 --- a/source4/kdc/mit_samba.c +++ b/source4/kdc/mit_samba.c @@ -482,7 +482,6 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx, DATA_BLOB *deleg_blob = NULL; struct samba_kdc_entry *client_skdc_entry = NULL; struct samba_kdc_entry *krbtgt_skdc_entry = NULL; - struct samba_kdc_entry *server_skdc_entry = NULL; bool is_in_db = false; bool is_untrusted = false; size_t num_types = 0; @@ -513,9 +512,6 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx, if (server == NULL) { return EINVAL; } - server_skdc_entry = - talloc_get_type_abort(server->e_data, - struct samba_kdc_entry); if (krbtgt == NULL) { return EINVAL; @@ -575,8 +571,7 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx, nt_status = samba_kdc_update_pac_blob(tmp_ctx, context, - krbtgt_skdc_entry, - server_skdc_entry, + krbtgt_skdc_entry->kdc_db_ctx->samdb, *pac, pac_blob, pac_srv_sig, diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index 04fbc5cf487..88bcb734fc5 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -747,8 +747,7 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx, NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, krb5_context context, - struct samba_kdc_entry *krbtgt, - struct samba_kdc_entry *server, + struct ldb_context *samdb, const krb5_pac pac, DATA_BLOB *pac_blob, struct PAC_SIGNATURE_DATA *pac_srv_sig, struct PAC_SIGNATURE_DATA *pac_kdc_sig) @@ -768,7 +767,7 @@ NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, * as the token might be generated by a trusted domain. */ nt_status = authsam_update_user_info_dc(mem_ctx, - krbtgt->kdc_db_ctx->samdb, + samdb, user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h index 2eb7fd3b755..7b51b0389f5 100644 --- a/source4/kdc/pac-glue.h +++ b/source4/kdc/pac-glue.h @@ -51,8 +51,7 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx, NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, krb5_context context, - struct samba_kdc_entry *krbtgt, - struct samba_kdc_entry *server, + struct ldb_context *samdb, const krb5_pac pac, DATA_BLOB *pac_blob, struct PAC_SIGNATURE_DATA *pac_srv_sig, struct PAC_SIGNATURE_DATA *pac_kdc_sig); diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index a7d8de1f417..68c8a8aa572 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -186,7 +186,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, } nt_status = samba_kdc_update_pac_blob(mem_ctx, context, - krbtgt_skdc_entry, p, + krbtgt_skdc_entry->kdc_db_ctx->samdb, *pac, pac_blob, pac_srv_sig, pac_kdc_sig); if (!NT_STATUS_IS_OK(nt_status)) { -- 2.25.1 From 7f289a20640fe7f12984701ba074a9895a5501e6 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 6 Oct 2021 16:40:21 +1300 Subject: [PATCH 121/162] s4:kdc: Fix debugging messages BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit c14c61748b5a2d2a4f4de00615c476fcf381309e) --- source4/kdc/wdc-samba4.c | 48 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 68c8a8aa572..037db40ce46 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -238,10 +238,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, switch (types[i]) { case PAC_TYPE_LOGON_INFO: if (logon_info_idx != -1) { - DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", - (int)types[i], - (int)logon_info_idx, - (int)i)); + DEBUG(1, ("logon info type[%"PRIu32"] twice [%zd] and [%zu]: \n", + types[i], + logon_info_idx, + i)); SAFE_FREE(types); talloc_free(mem_ctx); return EINVAL; @@ -250,10 +250,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, break; case PAC_TYPE_CONSTRAINED_DELEGATION: if (delegation_idx != -1) { - DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", - (int)types[i], - (int)logon_info_idx, - (int)i)); + DEBUG(1, ("constrained delegation type[%"PRIu32"] twice [%zd] and [%zu]: \n", + types[i], + delegation_idx, + i)); SAFE_FREE(types); talloc_free(mem_ctx); return EINVAL; @@ -262,10 +262,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, break; case PAC_TYPE_LOGON_NAME: if (logon_name_idx != -1) { - DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", - (int)types[i], - (int)logon_info_idx, - (int)i)); + DEBUG(1, ("logon name type[%"PRIu32"] twice [%zd] and [%zu]: \n", + types[i], + logon_name_idx, + i)); SAFE_FREE(types); talloc_free(mem_ctx); return EINVAL; @@ -274,10 +274,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, break; case PAC_TYPE_UPN_DNS_INFO: if (upn_dns_info_idx != -1) { - DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", - (int)types[i], - (int)logon_info_idx, - (int)i)); + DEBUG(1, ("upn dns info type[%"PRIu32"] twice [%zd] and [%zu]: \n", + types[i], + upn_dns_info_idx, + i)); SAFE_FREE(types); talloc_free(mem_ctx); return EINVAL; @@ -286,10 +286,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, break; case PAC_TYPE_SRV_CHECKSUM: if (srv_checksum_idx != -1) { - DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", - (int)types[i], - (int)logon_info_idx, - (int)i)); + DEBUG(1, ("server checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n", + types[i], + srv_checksum_idx, + i)); SAFE_FREE(types); talloc_free(mem_ctx); return EINVAL; @@ -298,10 +298,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, break; case PAC_TYPE_KDC_CHECKSUM: if (kdc_checksum_idx != -1) { - DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", - (int)types[i], - (int)logon_info_idx, - (int)i)); + DEBUG(1, ("kdc checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n", + types[i], + kdc_checksum_idx, + i)); SAFE_FREE(types); talloc_free(mem_ctx); return EINVAL; -- 2.25.1 From ee7f00da9bc590fc48c4a39fb1d534f8df495a94 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 15:42:29 +1300 Subject: [PATCH 122/162] s4/torture: Expect ticket checksum PAC buffer BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett [abartlet@samba.org backported from commit d5002c34ce1ffef795dc83af3175ca0e04d17dfd due to missing tests in Samba 4.14 that crashed the MIT KDC] --- selftest/knownfail_heimdal_kdc | 41 ++++++++++++++++++++++++++++++++ selftest/knownfail_mit_kdc | 41 ++++++++++++++++++++++++++++++++ source4/torture/rpc/remote_pac.c | 14 +++++++++-- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 0b8e83f1f3f..31572067ad4 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -154,3 +154,44 @@ # RODC tests # ^samba.tests.krb5.rodc_tests.samba.tests.krb5.rodc_tests.RodcKerberosTests.test_rodc_ticket_signature +# +# PAC tests +# +^netr-bdc-arcfour.verify-sig-arcfour +^netr-bdc-arcfour.verify-sig-arcfour +^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc:local +^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc_ntvfs:local +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008r2dc diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc index 4e0b20c5c80..09efbc7b590 100644 --- a/selftest/knownfail_mit_kdc +++ b/selftest/knownfail_mit_kdc @@ -329,3 +329,44 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_fast_no_etypes.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_no_sname.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_no_sname.ad_dc +# +# PAC tests +# +^netr-bdc-arcfour.verify-sig-arcfour +^netr-bdc-arcfour.verify-sig-arcfour +^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc:local +^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc_ntvfs:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc:local +^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc_ntvfs:local +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008r2dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2000dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2003dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008dc +^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008r2dc diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c index c74746123fe..14c23f674f1 100644 --- a/source4/torture/rpc/remote_pac.c +++ b/source4/torture/rpc/remote_pac.c @@ -266,7 +266,7 @@ static bool test_PACVerify(struct torture_context *tctx, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed"); - num_pac_buffers = 4; + num_pac_buffers = 5; if (expect_pac_upn_dns_info) { num_pac_buffers += 1; } @@ -317,6 +317,12 @@ static bool test_PACVerify(struct torture_context *tctx, pac_buf->info != NULL, "PAC_TYPE_KDC_CHECKSUM info"); + pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_TICKET_CHECKSUM); + torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_TICKET_CHECKSUM"); + torture_assert(tctx, + pac_buf->info != NULL, + "PAC_TYPE_TICKET_CHECKSUM info"); + ok = netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name, negotiate_flags, pac_data, session_info); @@ -1076,7 +1082,7 @@ static bool test_S4U2Proxy(struct torture_context *tctx, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed"); - num_pac_buffers = 6; + num_pac_buffers = 7; torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version"); torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers"); @@ -1101,6 +1107,10 @@ static bool test_S4U2Proxy(struct torture_context *tctx, torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_KDC_CHECKSUM"); torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_KDC_CHECKSUM info"); + pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_TICKET_CHECKSUM); + torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_TICKET_CHECKSUM"); + torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_TICKET_CHECKSUM info"); + pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CONSTRAINED_DELEGATION); torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CONSTRAINED_DELEGATION"); torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_CONSTRAINED_DELEGATION info"); -- 2.25.1 From 28dd954461e32719f7d58373a91ae9f4edd9b885 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Mon, 28 Dec 2020 22:07:10 +0200 Subject: [PATCH 123/162] kdc: remove KRB5SignedPath, to be replaced with PAC KRB5SignedPath was a Heimdal-specific authorization data element used to protect the authenticity of evidence tickets when used in constrained delegation (without a Windows PAC). Remove this, to be replaced with the Windows PAC which itself now supports signing the entire ticket in the TGS key. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Backported from Heimdal commit bb1d8f2a8c2545bccdf2c9179ce9259bf1050086 - Removed tests - Removed auditing hook (only present in Heimdal master) - Added knownfails ] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit ccabc7f16cca5b0dcb46233e934e708167f1071b) --- selftest/knownfail_heimdal_kdc | 6 + source4/heimdal/kdc/kerberos5.c | 12 -- source4/heimdal/kdc/krb5tgs.c | 297 ----------------------------- source4/heimdal/lib/asn1/krb5.asn1 | 21 -- 4 files changed, 6 insertions(+), 330 deletions(-) diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 31572067ad4..f0263133eee 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -130,6 +130,7 @@ # ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_missing_client_checksum +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_client_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_service_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_zeroed_client_checksum @@ -195,3 +196,8 @@ ^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2003dc ^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008dc ^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008r2dc +# +# The lack of KRB5SignedPath means we no longer return +# KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case +# +^samba4.krb5.kdc with machine account.as-req-pac-request.fl2000dc:local diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 0fa336e871c..a400b21a652 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -1744,18 +1744,6 @@ _kdc_as_rep(krb5_context context, _kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, et.endtime, et.renew_till); - /* do this as the last thing since this signs the EncTicketPart */ - ret = _kdc_add_KRB5SignedPath(context, - config, - server, - setype, - client->entry.principal, - NULL, - NULL, - &et); - if (ret) - goto out; - log_as_req(context, config, reply_key->keytype, setype, b); ret = _kdc_encode_reply(context, config, diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index d143eb739eb..c6bab82f517 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -47,230 +47,6 @@ get_krbtgt_realm(const PrincipalName *p) return NULL; } -/* - * The KDC might add a signed path to the ticket authorization data - * field. This is to avoid server impersonating clients and the - * request constrained delegation. - * - * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single - * entry of type KRB5SignedPath. - */ - -static krb5_error_code -find_KRB5SignedPath(krb5_context context, - const AuthorizationData *ad, - krb5_data *data) -{ - AuthorizationData child; - krb5_error_code ret; - int pos; - - if (ad == NULL || ad->len == 0) - return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; - - pos = ad->len - 1; - - if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT) - return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; - - ret = decode_AuthorizationData(ad->val[pos].ad_data.data, - ad->val[pos].ad_data.length, - &child, - NULL); - if (ret) { - krb5_set_error_message(context, ret, "Failed to decode " - "IF_RELEVANT with %d", ret); - return ret; - } - - if (child.len != 1) { - free_AuthorizationData(&child); - return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; - } - - if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) { - free_AuthorizationData(&child); - return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; - } - - if (data) - ret = der_copy_octet_string(&child.val[0].ad_data, data); - free_AuthorizationData(&child); - return ret; -} - -krb5_error_code -_kdc_add_KRB5SignedPath(krb5_context context, - krb5_kdc_configuration *config, - hdb_entry_ex *krbtgt, - krb5_enctype enctype, - krb5_principal client, - krb5_const_principal server, - krb5_principals principals, - EncTicketPart *tkt) -{ - krb5_error_code ret; - KRB5SignedPath sp; - krb5_data data; - krb5_crypto crypto = NULL; - size_t size = 0; - - if (server && principals) { - ret = add_Principals(principals, server); - if (ret) - return ret; - } - - { - KRB5SignedPathData spd; - - spd.client = client; - spd.authtime = tkt->authtime; - spd.delegated = principals; - spd.method_data = NULL; - - ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, - &spd, &size, ret); - if (ret) - return ret; - if (data.length != size) - krb5_abortx(context, "internal asn.1 encoder error"); - } - - { - Key *key; - ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key); - if (ret == 0) - ret = krb5_crypto_init(context, &key->key, 0, &crypto); - if (ret) { - free(data.data); - return ret; - } - } - - /* - * Fill in KRB5SignedPath - */ - - sp.etype = enctype; - sp.delegated = principals; - sp.method_data = NULL; - - ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0, - data.data, data.length, &sp.cksum); - krb5_crypto_destroy(context, crypto); - free(data.data); - if (ret) - return ret; - - ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret); - free_Checksum(&sp.cksum); - if (ret) - return ret; - if (data.length != size) - krb5_abortx(context, "internal asn.1 encoder error"); - - - /* - * Add IF-RELEVANT(KRB5SignedPath) to the last slot in - * authorization data field. - */ - - ret = _kdc_tkt_add_if_relevant_ad(context, tkt, - KRB5_AUTHDATA_SIGNTICKET, &data); - krb5_data_free(&data); - - return ret; -} - -static krb5_error_code -check_KRB5SignedPath(krb5_context context, - krb5_kdc_configuration *config, - hdb_entry_ex *krbtgt, - krb5_principal cp, - EncTicketPart *tkt, - krb5_principals *delegated, - int *signedpath) -{ - krb5_error_code ret; - krb5_data data; - krb5_crypto crypto = NULL; - - if (delegated) - *delegated = NULL; - - ret = find_KRB5SignedPath(context, tkt->authorization_data, &data); - if (ret == 0) { - KRB5SignedPathData spd; - KRB5SignedPath sp; - size_t size = 0; - - ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL); - krb5_data_free(&data); - if (ret) - return ret; - - spd.client = cp; - spd.authtime = tkt->authtime; - spd.delegated = sp.delegated; - spd.method_data = sp.method_data; - - ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, - &spd, &size, ret); - if (ret) { - free_KRB5SignedPath(&sp); - return ret; - } - if (data.length != size) - krb5_abortx(context, "internal asn.1 encoder error"); - - { - Key *key; - ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key); - if (ret == 0) - ret = krb5_crypto_init(context, &key->key, 0, &crypto); - if (ret) { - free(data.data); - free_KRB5SignedPath(&sp); - return ret; - } - } - ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, - data.data, data.length, - &sp.cksum); - krb5_crypto_destroy(context, crypto); - free(data.data); - if (ret) { - free_KRB5SignedPath(&sp); - kdc_log(context, config, 5, - "KRB5SignedPath not signed correctly, not marking as signed"); - return 0; - } - - if (delegated && sp.delegated) { - - *delegated = malloc(sizeof(*sp.delegated)); - if (*delegated == NULL) { - free_KRB5SignedPath(&sp); - return ENOMEM; - } - - ret = copy_Principals(*delegated, sp.delegated); - if (ret) { - free_KRB5SignedPath(&sp); - free(*delegated); - *delegated = NULL; - return ret; - } - } - free_KRB5SignedPath(&sp); - - *signedpath = 1; - } - - return 0; -} - /* * */ @@ -738,7 +514,6 @@ tgs_make_reply(krb5_context context, krb5_principal client_principal, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, - krb5_principals spp, const krb5_data *rspac, const METHOD_DATA *enc_pa_data, const char **e_text, @@ -903,20 +678,6 @@ tgs_make_reply(krb5_context context, goto out; } } - - /* Filter out type KRB5SignedPath */ - ret = find_KRB5SignedPath(context, et.authorization_data, NULL); - if (ret == 0) { - if (et.authorization_data->len == 1) { - free_AuthorizationData(et.authorization_data); - free(et.authorization_data); - et.authorization_data = NULL; - } else { - AuthorizationData *ad = et.authorization_data; - free_AuthorizationDataElement(&ad->val[ad->len - 1]); - ad->len--; - } - } } ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key); @@ -945,24 +706,6 @@ tgs_make_reply(krb5_context context, _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, et.endtime, et.renew_till); - /* Don't sign cross realm tickets, they can't be checked anyway */ - { - char *r = get_krbtgt_realm(&ek.sname); - - if (r == NULL || strcmp(r, ek.srealm) == 0) { - ret = _kdc_add_KRB5SignedPath(context, - config, - krbtgt, - krbtgt_etype, - client_principal, - NULL, - spp, - &et); - if (ret) - goto out; - } - } - if (enc_pa_data->len) { rep.padata = calloc(1, sizeof(*rep.padata)); if (rep.padata == NULL) { @@ -1517,7 +1260,6 @@ tgs_build_reply(krb5_context context, HDB *clientdb, *s4u2self_impersonated_clientdb; krb5_realm ref_realm = NULL; EncTicketPart *tgt = &ticket->ticket; - krb5_principals spp = NULL; const EncryptionKey *ekey; krb5_keyblock sessionkey; krb5_kvno kvno; @@ -1891,23 +1633,6 @@ server_lookup: goto out; } - /* also check the krbtgt for signature */ - ret = check_KRB5SignedPath(context, - config, - krbtgt, - cp, - tgt, - &spp, - &signedpath); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 0, - "KRB5SignedPath check failed for %s (%s) from %s with %s", - spn, cpn, from, msg); - krb5_free_error_message(context, msg); - goto out; - } - /* * Process request */ @@ -2200,27 +1925,6 @@ server_lookup: goto out; } - /* - * Check that the KDC issued the user's ticket. - */ - ret = check_KRB5SignedPath(context, - config, - krbtgt, - cp, - &adtkt, - NULL, - &ad_signedpath); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 0, - "KRB5SignedPath check from service %s failed " - "for delegation to %s for client %s (%s)" - "from %s failed with %s", - spn, tpn, dpn, cpn, from, msg); - krb5_free_error_message(context, msg); - goto out; - } - if (!ad_signedpath) { ret = KRB5KDC_ERR_BADOPTION; kdc_log(context, config, 0, @@ -2318,7 +2022,6 @@ server_lookup: cp, krbtgt_out, krbtgt_etype, - spp, &rspac, &enc_pa_data, e_text, diff --git a/source4/heimdal/lib/asn1/krb5.asn1 b/source4/heimdal/lib/asn1/krb5.asn1 index c2f40c0ecd6..155d51d4ac8 100644 --- a/source4/heimdal/lib/asn1/krb5.asn1 +++ b/source4/heimdal/lib/asn1/krb5.asn1 @@ -43,9 +43,6 @@ EXPORTS KRB-PRIV, KRB-SAFE, KRB-SAFE-BODY, - KRB5SignedPath, - KRB5SignedPathData, - KRB5SignedPathPrincipals, KerberosString, KerberosTime, KrbCredInfo, @@ -713,24 +710,6 @@ PA-S4U2Self ::= SEQUENCE { auth[3] GeneralString } --- never encoded on the wire, just used to checksum over -KRB5SignedPathData ::= SEQUENCE { - client[0] Principal OPTIONAL, - authtime[1] KerberosTime, - delegated[2] Principals OPTIONAL, - method_data[3] METHOD-DATA OPTIONAL -} - -KRB5SignedPath ::= SEQUENCE { - -- DERcoded KRB5SignedPathData - -- krbtgt key (etype), KeyUsage = XXX - etype[0] ENCTYPE, - cksum[1] Checksum, - -- srvs delegated though - delegated[2] Principals OPTIONAL, - method_data[3] METHOD-DATA OPTIONAL -} - AD-LoginAlias ::= SEQUENCE { -- ad-type number TBD -- login-alias [0] PrincipalName, checksum [1] Checksum -- 2.25.1 From a8df96e2baa6cd867c5d1f8e691518f1ad0123ae Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Fri, 13 Aug 2021 12:44:37 +0300 Subject: [PATCH 124/162] kdc: sign ticket using Windows PAC Split Windows PAC signing and verification logic, as the signing has to be when the ticket is ready. Create sign and verify the PAC KDC signature if the plugin did not, allowing for S4U2Proxy to work, instead of KRB5SignedPath. Use the header key to verify PAC server signature, as the same key used to encrypt/decrypt the ticket should be used for PAC server signature, like U2U tickets are signed witht the tgt session-key and not with the longterm key, and so krbtgt should be no different and the header key should be used. Lookup the delegated client in DB instead of passing the delegator DB entry. Add PAC ticket-signatures and related functions. Note: due to the change from KRB5SignedPath to PAC, S4U2Proxy requests against new KDC will not work if the evidence ticket was acquired from an old KDC, and vide versa. Closes: #767 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Backported from Heimdal commit 2ffaba9401d19c718764d4bd24180960290238e9 - Removed tests - Adapted to Samba's version of Heimdal - Addressed build failures with -O3 - Added knownfails ] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett [abartlet@samba.org backported from commit d7b03394a9012960d71489e775d40d10fd6f5232 due to conflicts in knownfail due to missing tests that crash the MIT KDC] --- selftest/knownfail_heimdal_kdc | 54 +-- source4/heimdal/kdc/kerberos5.c | 69 +--- source4/heimdal/kdc/krb5tgs.c | 354 +++++++++--------- source4/heimdal/kdc/windc.c | 15 +- source4/heimdal/kdc/windc_plugin.h | 5 +- source4/heimdal/lib/krb5/authdata.c | 124 +++++++ source4/heimdal/lib/krb5/pac.c | 376 ++++++++++++++++++-- source4/heimdal/lib/krb5/version-script.map | 5 + source4/heimdal_build/wscript_build | 2 +- source4/selftest/tests.py | 2 +- 10 files changed, 687 insertions(+), 319 deletions(-) create mode 100644 source4/heimdal/lib/krb5/authdata.c diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index f0263133eee..4ec682c01d0 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -1,7 +1,7 @@ # # We expect all the MIT specific compatability tests to fail on heimdal # kerberos -^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_mit_(?!ticket_signature) +^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_mit_ # # Heimdal currently fails the following MS-KILE client principal lookup # tests @@ -122,14 +122,9 @@ ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_no_sname.ad_dc ^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_sname.ad_dc # -# Heimdal currently does not generate ticket signatures -# -^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_heimdal_ticket_signature -# # S4U tests # ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_missing_client_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_client_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_service_checksum @@ -143,60 +138,13 @@ ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_unkeyed_service_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_client_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_service_checksum -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_client_not_delegated ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_forwardable -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_forwardable ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_empty_allowed -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_nonempty_allowed -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_trusted_empty_allowed -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_trusted_nonempty_allowed -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_without_forwardable # # RODC tests # ^samba.tests.krb5.rodc_tests.samba.tests.krb5.rodc_tests.RodcKerberosTests.test_rodc_ticket_signature # -# PAC tests -# -^netr-bdc-arcfour.verify-sig-arcfour -^netr-bdc-arcfour.verify-sig-arcfour -^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc:local -^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc_ntvfs:local -^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc:local -^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc_ntvfs:local -^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc:local -^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc_ntvfs:local -^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc:local -^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc_ntvfs:local -^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc:local -^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc_ntvfs:local -^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc:local -^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc_ntvfs:local -^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2000dc -^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2003dc -^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008dc -^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008r2dc -^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2000dc -^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2003dc -^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008dc -^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008r2dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2000dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2003dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008r2dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2000dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2003dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008dc -^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008r2dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2000dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2003dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008r2dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2000dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2003dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008dc -^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008r2dc -# # The lack of KRB5SignedPath means we no longer return # KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case # diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index a400b21a652..7b17d2539ce 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -1712,6 +1712,7 @@ _kdc_as_rep(krb5_context context, if (send_pac_p(context, req)) { krb5_pac p = NULL; krb5_data data; + uint16_t rodc_id; ret = _kdc_pac_generate(context, client, pk_reply_key, &p); if (ret) { @@ -1720,10 +1721,13 @@ _kdc_as_rep(krb5_context context, goto out; } if (p != NULL) { + rodc_id = server->entry.kvno >> 16; + ret = _krb5_pac_sign(context, p, et.authtime, client->entry.principal, &skey->key, /* Server key */ &skey->key, /* FIXME: should be krbtgt key */ + rodc_id, &data); krb5_pac_free(context, p); if (ret) { @@ -1732,9 +1736,7 @@ _kdc_as_rep(krb5_context context, goto out; } - ret = _kdc_tkt_add_if_relevant_ad(context, &et, - KRB5_AUTHDATA_WIN2K_PAC, - &data); + ret = _kdc_tkt_insert_pac(context, &et, &data); krb5_data_free(&data); if (ret) goto out; @@ -1888,64 +1890,3 @@ prepare_enc_data(krb5_context context, return TRUE; } - -/* - * Add the AuthorizationData `data´ of `type´ to the last element in - * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT - */ - -krb5_error_code -_kdc_tkt_add_if_relevant_ad(krb5_context context, - EncTicketPart *tkt, - int type, - const krb5_data *data) -{ - krb5_error_code ret; - size_t size = 0; - - if (tkt->authorization_data == NULL) { - tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data)); - if (tkt->authorization_data == NULL) { - krb5_set_error_message(context, ENOMEM, "out of memory"); - return ENOMEM; - } - } - - /* add the entry to the last element */ - { - AuthorizationData ad = { 0, NULL }; - AuthorizationDataElement ade; - - ade.ad_type = type; - ade.ad_data = *data; - - ret = add_AuthorizationData(&ad, &ade); - if (ret) { - krb5_set_error_message(context, ret, "add AuthorizationData failed"); - return ret; - } - - ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT; - - ASN1_MALLOC_ENCODE(AuthorizationData, - ade.ad_data.data, ade.ad_data.length, - &ad, &size, ret); - free_AuthorizationData(&ad); - if (ret) { - krb5_set_error_message(context, ret, "ASN.1 encode of " - "AuthorizationData failed"); - return ret; - } - if (ade.ad_data.length != size) - krb5_abortx(context, "internal asn.1 encoder error"); - - ret = add_AuthorizationData(tkt->authorization_data, &ade); - der_free_octet_string(&ade.ad_data); - if (ret) { - krb5_set_error_message(context, ret, "add AuthorizationData failed"); - return ret; - } - } - - return 0; -} diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index c6bab82f517..3b35b828402 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -59,85 +59,64 @@ check_PAC(krb5_context context, hdb_entry_ex *client, hdb_entry_ex *server, hdb_entry_ex *krbtgt, + hdb_entry_ex *ticket_server, const EncryptionKey *server_check_key, - const EncryptionKey *server_sign_key, - const EncryptionKey *krbtgt_sign_key, + const EncryptionKey *krbtgt_check_key, EncTicketPart *tkt, - krb5_data *rspac, - int *signedpath) + krb5_boolean *kdc_issued, + krb5_pac *ppac) { - AuthorizationData *ad = tkt->authorization_data; - unsigned i, j; + krb5_pac pac = NULL; krb5_error_code ret; + krb5_boolean signedticket; - if (ad == NULL || ad->len == 0) - return 0; - - for (i = 0; i < ad->len; i++) { - AuthorizationData child; - - if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) - continue; - - ret = decode_AuthorizationData(ad->val[i].ad_data.data, - ad->val[i].ad_data.length, - &child, - NULL); - if (ret) { - krb5_set_error_message(context, ret, "Failed to decode " - "IF_RELEVANT with %d", ret); - return ret; - } - for (j = 0; j < child.len; j++) { - - if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { - int signed_pac = 0; - krb5_pac pac; - - /* Found PAC */ - ret = krb5_pac_parse(context, - child.val[j].ad_data.data, - child.val[j].ad_data.length, - &pac); - free_AuthorizationData(&child); - if (ret) - return ret; + *kdc_issued = FALSE; + *ppac = NULL; - ret = krb5_pac_verify(context, pac, tkt->authtime, - client_principal, - server_check_key, NULL); - if (ret) { - krb5_pac_free(context, pac); - return ret; - } + ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac); + if (ret || pac == NULL) + return ret; - ret = _kdc_pac_verify(context, client_principal, - delegated_proxy_principal, - client, server, krbtgt, &pac, &signed_pac); - if (ret) { - krb5_pac_free(context, pac); - return ret; - } + /* Verify the server signature. */ + ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal, + server_check_key, NULL); + if (ret) { + krb5_pac_free(context, pac); + return ret; + } - /* - * Only re-sign PAC if we could verify it with the PAC - * function. The no-verify case happens when we get in - * a PAC from cross realm from a Windows domain and - * that there is no PAC verification function. - */ - if (signed_pac) { - *signedpath = 1; - ret = _krb5_pac_sign(context, pac, tkt->authtime, - client_principal, - server_sign_key, krbtgt_sign_key, rspac); - } + /* Verify the KDC signatures. */ + ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal, + client, server, krbtgt, &pac); + if (ret == KRB5_PLUGIN_NO_HANDLE) { + /* + * We can't verify the KDC signatures if the ticket was issued by + * another realm's KDC. + */ + if (krb5_realm_compare(context, server->entry.principal, + ticket_server->entry.principal)) { + ret = krb5_pac_verify(context, pac, 0, NULL, NULL, + krbtgt_check_key); + if (ret) { krb5_pac_free(context, pac); - return ret; } } - free_AuthorizationData(&child); + /* Discard the PAC if the plugin didn't handle it */ + krb5_pac_free(context, pac); + ret = krb5_pac_init(context, &pac); + if (ret) + return ret; + } else if (ret) { + krb5_pac_free(context, pac); + return ret; } + + *kdc_issued = signedticket || + krb5_principal_is_krbtgt(context, + ticket_server->entry.principal); + *ppac = pac; + return 0; } @@ -499,11 +478,12 @@ static krb5_error_code tgs_make_reply(krb5_context context, krb5_kdc_configuration *config, KDC_REQ_BODY *b, - krb5_const_principal tgt_name, + krb5_principal tgt_name, const EncTicketPart *tgt, const krb5_keyblock *replykey, int rk_is_subkey, const EncryptionKey *serverkey, + const EncryptionKey *krbtgtkey, const krb5_keyblock *sessionkey, krb5_kvno kvno, AuthorizationData *auth_data, @@ -513,8 +493,9 @@ tgs_make_reply(krb5_context context, hdb_entry_ex *client, krb5_principal client_principal, hdb_entry_ex *krbtgt, - krb5_enctype krbtgt_etype, - const krb5_data *rspac, + krb5_pac mspac, + uint16_t rodc_id, + krb5_boolean add_ticket_sig, const METHOD_DATA *enc_pa_data, const char **e_text, krb5_data *reply) @@ -647,17 +628,6 @@ tgs_make_reply(krb5_context context, if (!server->entry.flags.proxiable) et.flags.proxiable = 0; - if(rspac->length) { - /* - * No not need to filter out the any PAC from the - * auth_data since it's signed by the KDC. - */ - ret = _kdc_tkt_add_if_relevant_ad(context, &et, - KRB5_AUTHDATA_WIN2K_PAC, rspac); - if (ret) - goto out; - } - if (auth_data) { unsigned int i = 0; @@ -724,6 +694,11 @@ tgs_make_reply(krb5_context context, is_weak = 1; } + /* The PAC should be the last change to the ticket. */ + ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey, + krbtgtkey, rodc_id, add_ticket_sig, &et); + if (ret) + goto out; /* It is somewhat unclear where the etype in the following encryption should come from. What we have is a session @@ -910,6 +885,7 @@ tgs_parse_request(krb5_context context, int **cusec, AuthorizationData **auth_data, krb5_keyblock **replykey, + Key **header_key, int *rk_is_subkey) { static char failed[] = ""; @@ -1047,6 +1023,8 @@ tgs_parse_request(krb5_context context, goto out; } + *header_key = tkey; + { krb5_authenticator auth; @@ -1236,6 +1214,57 @@ eout: return ENOMEM; } +static krb5_error_code +db_fetch_client(krb5_context context, + krb5_kdc_configuration *config, + int flags, + krb5_principal cp, + const char *cpn, + const char *krbtgt_realm, + HDB **clientdb, + hdb_entry_ex **client_out) +{ + krb5_error_code ret; + hdb_entry_ex *client = NULL; + + *client_out = NULL; + + ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags, + NULL, clientdb, &client); + if (ret == HDB_ERR_NOT_FOUND_HERE) { + /* + * This is OK, we are just trying to find out if they have + * been disabled or deleted in the meantime; missing secrets + * are OK. + */ + } else if (ret) { + /* + * If the client belongs to the same realm as our TGS, it + * should exist in the local database. + */ + const char *msg; + + if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) { + if (ret == HDB_ERR_NOENTRY) + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; + kdc_log(context, config, 4, "Client no longer in database: %s", cpn); + return ret; + } + + msg = krb5_get_error_message(context, ret); + kdc_log(context, config, 4, "Client not found in database: %s", msg); + krb5_free_error_message(context, msg); + } else if (client->entry.flags.invalid || !client->entry.flags.client) { + kdc_log(context, config, 4, "Client has invalid bit set"); + _kdc_free_ent(context, client); + return KRB5KDC_ERR_POLICY; + } + + *client_out = client; + + return 0; +} + static krb5_error_code tgs_build_reply(krb5_context context, krb5_kdc_configuration *config, @@ -1243,6 +1272,7 @@ tgs_build_reply(krb5_context context, KDC_REQ_BODY *b, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, + Key *tkey_check, const krb5_keyblock *replykey, int rk_is_subkey, krb5_ticket *ticket, @@ -1263,7 +1293,9 @@ tgs_build_reply(krb5_context context, const EncryptionKey *ekey; krb5_keyblock sessionkey; krb5_kvno kvno; - krb5_data rspac; + krb5_pac mspac = NULL; + uint16_t rodc_id; + krb5_boolean add_ticket_sig = FALSE; hdb_entry_ex *krbtgt_out = NULL; @@ -1274,15 +1306,13 @@ tgs_build_reply(krb5_context context, int nloop = 0; EncTicketPart adtkt; char opt_str[128]; - int signedpath = 0; + krb5_boolean kdc_issued = FALSE; - Key *tkey_check; Key *tkey_sign; int flags = HDB_F_FOR_TGS_REQ; memset(&sessionkey, 0, sizeof(sessionkey)); memset(&adtkt, 0, sizeof(adtkt)); - krb5_data_zero(&rspac); memset(&enc_pa_data, 0, sizeof(enc_pa_data)); s = b->sname; @@ -1517,18 +1547,6 @@ server_lookup: * backward. */ - /* - * Validate authoriation data - */ - - ret = hdb_enctype2key(context, &krbtgt->entry, - krbtgt_etype, &tkey_check); - if(ret) { - kdc_log(context, config, 0, - "Failed to find key for krbtgt PAC check"); - goto out; - } - /* Now refetch the primary krbtgt, and get the current kvno (the * sign check may have been on an old kvno, and the server may * have been an incoming trust) */ @@ -1589,41 +1607,14 @@ server_lookup: goto out; } - ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags, - NULL, &clientdb, &client); - if(ret == HDB_ERR_NOT_FOUND_HERE) { - /* This is OK, we are just trying to find out if they have - * been disabled or deleted in the meantime, missing secrets - * is OK */ - } else if(ret){ - const char *krbtgt_realm, *msg; - - /* - * If the client belongs to the same realm as our krbtgt, it - * should exist in the local database. - * - */ - - krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal); - - if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) { - if (ret == HDB_ERR_NOENTRY) - ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; - kdc_log(context, config, 1, "Client no longer in database: %s", - cpn); - goto out; - } - - msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 1, "Client not found in database: %s", msg); - krb5_free_error_message(context, msg); - } + ret = db_fetch_client(context, config, flags, cp, cpn, + krb5_principal_get_realm(context, krbtgt_out->entry.principal), + &clientdb, &client); + if (ret) + goto out; - ret = check_PAC(context, config, cp, NULL, - client, server, krbtgt, - &tkey_check->key, - ekey, &tkey_sign->key, - tgt, &rspac, &signedpath); + ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt, + &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac); if (ret) { const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, @@ -1760,27 +1751,15 @@ server_lookup: goto out; /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */ - if(rspac.data) { - krb5_pac p = NULL; - krb5_data_free(&rspac); - ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &p); + if (mspac) { + krb5_pac_free(context, mspac); + mspac = NULL; + ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &mspac); if (ret) { kdc_log(context, config, 0, "PAC generation failed for -- %s", tpn); goto out; } - if (p != NULL) { - ret = _krb5_pac_sign(context, p, ticket->ticket.authtime, - s4u2self_impersonated_client->entry.principal, - ekey, &tkey_sign->key, - &rspac); - krb5_pac_free(context, p); - if (ret) { - kdc_log(context, config, 0, "PAC signing failed for -- %s", - tpn); - goto out; - } - } } /* @@ -1823,22 +1802,25 @@ server_lookup: && b->additional_tickets->len != 0 && b->kdc_options.enc_tkt_in_skey == 0) { - int ad_signedpath = 0; + hdb_entry_ex *adclient = NULL; + krb5_boolean ad_kdc_issued = FALSE; Key *clientkey; Ticket *t; /* - * Require that the KDC have issued the service's krbtgt (not - * self-issued ticket with kimpersonate(1). + * We require that the service's krbtgt has a PAC. */ - if (!signedpath) { + if (mspac == NULL) { ret = KRB5KDC_ERR_BADOPTION; kdc_log(context, config, 0, - "Constrained delegation done on service ticket %s/%s", + "Constrained delegation without PAC %s/%s", cpn, spn); goto out; } + krb5_pac_free(context, mspac); + mspac = NULL; + t = &b->additional_tickets->val[0]; ret = hdb_enctype2key(context, &client->entry, @@ -1902,19 +1884,32 @@ server_lookup: goto out; } - krb5_data_free(&rspac); + /* Try lookup the delegated client in DB */ + ret = db_fetch_client(context, config, flags, tp, tpn, + krb5_principal_get_realm(context, krbtgt_out->entry.principal), + NULL, &adclient); + if (ret) + goto out; + + if (adclient != NULL) { + ret = kdc_check_flags(context, config, + adclient, tpn, + server, spn, + FALSE); + if (ret) { + _kdc_free_ent(context, adclient); + goto out; + } + } /* - * generate the PAC for the user. - * * TODO: pass in t->sname and t->realm and build * a S4U_DELEGATION_INFO blob to the PAC. */ - ret = check_PAC(context, config, tp, dp, - client, server, krbtgt, - &clientkey->key, - ekey, &tkey_sign->key, - &adtkt, &rspac, &ad_signedpath); + ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client, + &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac); + if (adclient) + _kdc_free_ent(context, adclient); if (ret) { const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, @@ -1925,13 +1920,12 @@ server_lookup: goto out; } - if (!ad_signedpath) { + if (mspac == NULL || !ad_kdc_issued) { ret = KRB5KDC_ERR_BADOPTION; kdc_log(context, config, 0, - "Ticket not signed with PAC nor SignedPath service %s failed " - "for delegation to %s for client %s (%s)" - "from %s", - spn, tpn, dpn, cpn, from); + "Ticket not signed with PAC; service %s failed for " + "for delegation to %s for client %s (%s) from %s; (%s).", + spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC"); goto out; } @@ -2000,6 +1994,25 @@ server_lookup: } } + /* + * Only add ticket signature if the requested server is not krbtgt, and + * either the header server is krbtgt or, in the case of renewal/validation + * if it was signed with PAC ticket signature and we verified it. + * Currently Heimdal only allows renewal of krbtgt anyway but that might + * change one day (see issue #763) so make sure to check for it. + */ + + if (kdc_issued && + !krb5_principal_is_krbtgt(context, server->entry.principal)) + add_ticket_sig = TRUE; + + /* + * Active-Directory implementations use the high part of the kvno as the + * read-only-dc identifier, we need to embed it in the PAC KDC signatures. + */ + + rodc_id = krbtgt_out->entry.kvno >> 16; + /* * */ @@ -2012,6 +2025,7 @@ server_lookup: replykey, rk_is_subkey, ekey, + &tkey_sign->key, &sessionkey, kvno, *auth_data, @@ -2021,8 +2035,9 @@ server_lookup: client, cp, krbtgt_out, - krbtgt_etype, - &rspac, + mspac, + rodc_id, + add_ticket_sig, &enc_pa_data, e_text, reply); @@ -2035,7 +2050,6 @@ out: if (dpn) free(dpn); - krb5_data_free(&rspac); krb5_free_keyblock_contents(context, &sessionkey); if(krbtgt_out) _kdc_free_ent(context, krbtgt_out); @@ -2060,6 +2074,9 @@ out: free_EncTicketPart(&adtkt); + if (mspac) + krb5_pac_free(context, mspac); + return ret; } @@ -2080,6 +2097,7 @@ _kdc_tgs_rep(krb5_context context, krb5_error_code ret; int i = 0; const PA_DATA *tgs_req; + Key *header_key = NULL; hdb_entry_ex *krbtgt = NULL; krb5_ticket *ticket = NULL; @@ -2117,6 +2135,7 @@ _kdc_tgs_rep(krb5_context context, &csec, &cusec, &auth_data, &replykey, + &header_key, &rk_is_subkey); if (ret == HDB_ERR_NOT_FOUND_HERE) { /* kdc_log() is called in tgs_parse_request() */ @@ -2134,6 +2153,7 @@ _kdc_tgs_rep(krb5_context context, &req->req_body, krbtgt, krbtgt_etype, + header_key, replykey, rk_is_subkey, ticket, diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c index fb1c8a6a993..43dc89e2bc0 100644 --- a/source4/heimdal/kdc/windc.c +++ b/source4/heimdal/kdc/windc.c @@ -77,8 +77,14 @@ _kdc_pac_generate(krb5_context context, krb5_pac *pac) { *pac = NULL; - if (windcft == NULL) + if (krb5_config_get_bool_default(context, NULL, FALSE, "realms", + client->entry.principal->realm, + "disable_pac", NULL)) return 0; + if (windcft == NULL) { + return krb5_pac_init(context, pac); + } + if (windcft->pac_pk_generate != NULL && pk_reply_key != NULL) return (windcft->pac_pk_generate)(windcctx, context, client, pk_reply_key, pac); @@ -92,20 +98,17 @@ _kdc_pac_verify(krb5_context context, hdb_entry_ex *client, hdb_entry_ex *server, hdb_entry_ex *krbtgt, - krb5_pac *pac, - int *verified) + krb5_pac *pac) { krb5_error_code ret; if (windcft == NULL) - return 0; + return KRB5_PLUGIN_NO_HANDLE; ret = windcft->pac_verify(windcctx, context, client_principal, delegated_proxy_principal, client, server, krbtgt, pac); - if (ret == 0) - *verified = 1; return ret; } diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h index bf90826cb06..dda258da3d1 100644 --- a/source4/heimdal/kdc/windc_plugin.h +++ b/source4/heimdal/kdc/windc_plugin.h @@ -43,8 +43,9 @@ * krb5_pac_init and fill in the PAC structure for the principal using * krb5_pac_add_buffer. * - * The PAC verify function should verify all components in the PAC - * using krb5_pac_get_types and krb5_pac_get_buffer for all types. + * The PAC verify function should verify the PAC KDC signatures by fetching + * the right KDC key and calling krb5_pac_verify() with that KDC key. + * Optionally, update the PAC buffers upon success. * * Check client access function check if the client is authorized. */ diff --git a/source4/heimdal/lib/krb5/authdata.c b/source4/heimdal/lib/krb5/authdata.c new file mode 100644 index 00000000000..ac426618f6e --- /dev/null +++ b/source4/heimdal/lib/krb5/authdata.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1997-2021 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Copyright (c) 2021 Isaac Boukris + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * Add the AuthorizationData `data´ of `type´ to the last element in + * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_kdc_tkt_add_if_relevant_ad(krb5_context context, + EncTicketPart *tkt, + int type, + const krb5_data *data) +{ + krb5_error_code ret; + size_t size = 0; + + if (tkt->authorization_data == NULL) { + tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data)); + if (tkt->authorization_data == NULL) { + return krb5_enomem(context); + } + } + + /* add the entry to the last element */ + { + AuthorizationData ad = { 0, NULL }; + AuthorizationDataElement ade; + + ade.ad_type = type; + ade.ad_data = *data; + + ret = add_AuthorizationData(&ad, &ade); + if (ret) { + krb5_set_error_message(context, ret, "add AuthorizationData failed"); + return ret; + } + + ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT; + + ASN1_MALLOC_ENCODE(AuthorizationData, + ade.ad_data.data, ade.ad_data.length, + &ad, &size, ret); + free_AuthorizationData(&ad); + if (ret) { + krb5_set_error_message(context, ret, "ASN.1 encode of " + "AuthorizationData failed"); + return ret; + } + if (ade.ad_data.length != size) + krb5_abortx(context, "internal asn.1 encoder error"); + + ret = add_AuthorizationData(tkt->authorization_data, &ade); + der_free_octet_string(&ade.ad_data); + if (ret) { + krb5_set_error_message(context, ret, "add AuthorizationData failed"); + return ret; + } + } + + return 0; +} + +/* + * Insert a PAC wrapped in AD-IF-RELEVANT container as the first AD element, + * as some clients such as Windows may fail to parse it otherwise. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_kdc_tkt_insert_pac(krb5_context context, + EncTicketPart *tkt, + const krb5_data *data) +{ + AuthorizationDataElement ade; + unsigned int i; + krb5_error_code ret; + + ret = _kdc_tkt_add_if_relevant_ad(context, tkt, KRB5_AUTHDATA_WIN2K_PAC, + data); + if (ret) + return ret; + + heim_assert(tkt->authorization_data->len != 0, "No authorization_data!"); + ade = tkt->authorization_data->val[tkt->authorization_data->len - 1]; + for (i = 0; i < tkt->authorization_data->len - 1; i++) { + tkt->authorization_data->val[i + 1] = tkt->authorization_data->val[i]; + } + tkt->authorization_data->val[0] = ade; + + return 0; +} diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index 26aae107b32..eec1e84c7bd 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -53,6 +53,8 @@ struct krb5_pac_data { struct PAC_INFO_BUFFER *server_checksum; struct PAC_INFO_BUFFER *privsvr_checksum; struct PAC_INFO_BUFFER *logon_name; + struct PAC_INFO_BUFFER *ticket_checksum; + krb5_data ticket_sign_data; }; #define PAC_ALIGNMENT 8 @@ -64,6 +66,7 @@ struct krb5_pac_data { #define PAC_PRIVSVR_CHECKSUM 7 #define PAC_LOGON_NAME 10 #define PAC_CONSTRAINED_DELEGATION 11 +#define PAC_TICKET_CHECKSUM 16 #define CHECK(r,f,l) \ do { \ @@ -142,13 +145,13 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len, CHECK(ret, krb5_ret_uint32(sp, &tmp2), out); if (tmp < 1) { ret = EINVAL; /* Too few buffers */ - krb5_set_error_message(context, ret, N_("PAC have too few buffer", "")); + krb5_set_error_message(context, ret, N_("PAC has too few buffers", "")); goto out; } if (tmp2 != 0) { ret = EINVAL; /* Wrong version */ krb5_set_error_message(context, ret, - N_("PAC have wrong version %d", ""), + N_("PAC has wrong version %d", ""), (int)tmp2); goto out; } @@ -191,7 +194,7 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len, if (p->pac->buffers[i].offset_lo > len) { ret = EINVAL; krb5_set_error_message(context, ret, - N_("PAC offset off end", "")); + N_("PAC offset overflow", "")); goto out; } if (p->pac->buffers[i].offset_lo < header_end) { @@ -204,7 +207,7 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len, } if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){ ret = EINVAL; - krb5_set_error_message(context, ret, N_("PAC length off end", "")); + krb5_set_error_message(context, ret, N_("PAC length overflow", "")); goto out; } @@ -213,7 +216,7 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len, if (p->server_checksum) { ret = EINVAL; krb5_set_error_message(context, ret, - N_("PAC have two server checksums", "")); + N_("PAC has multiple server checksums", "")); goto out; } p->server_checksum = &p->pac->buffers[i]; @@ -221,7 +224,7 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len, if (p->privsvr_checksum) { ret = EINVAL; krb5_set_error_message(context, ret, - N_("PAC have two KDC checksums", "")); + N_("PAC has multiple KDC checksums", "")); goto out; } p->privsvr_checksum = &p->pac->buffers[i]; @@ -229,10 +232,18 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len, if (p->logon_name) { ret = EINVAL; krb5_set_error_message(context, ret, - N_("PAC have two logon names", "")); + N_("PAC has multiple logon names", "")); goto out; } p->logon_name = &p->pac->buffers[i]; + } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) { + if (p->ticket_checksum) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("PAC has multiple ticket checksums", "")); + goto out; + } + p->ticket_checksum = &p->pac->buffers[i]; } } @@ -425,6 +436,7 @@ KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_pac_free(krb5_context context, krb5_pac pac) { krb5_data_free(&pac->data); + krb5_data_free(&pac->ticket_sign_data); free(pac->pac); free(pac); } @@ -444,6 +456,7 @@ verify_checksum(krb5_context context, uint32_t type; krb5_error_code ret; Checksum cksum; + size_t cksumsize; memset(&cksum, 0, sizeof(cksum)); @@ -456,8 +469,17 @@ verify_checksum(krb5_context context, CHECK(ret, krb5_ret_uint32(sp, &type), out); cksum.cksumtype = type; - cksum.checksum.length = - sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR); + + ret = krb5_checksumsize(context, type, &cksumsize); + if (ret) + goto out; + + /* Allow for RODCIdentifier trailer, see MS-PAC 2.8 */ + if (cksumsize > (sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR))) { + ret = EINVAL; + goto out; + } + cksum.checksum.length = cksumsize; cksum.checksum.data = malloc(cksum.checksum.length); if (cksum.checksum.data == NULL) { ret = krb5_enomem(context); @@ -804,7 +826,6 @@ out: return ret; } - /** * Verify the PAC. * @@ -844,18 +865,22 @@ krb5_pac_verify(krb5_context context, return EINVAL; } - ret = verify_logonname(context, - pac->logon_name, - &pac->data, - authtime, - principal); - if (ret) - return ret; + if (principal != NULL) { + ret = verify_logonname(context, pac->logon_name, &pac->data, authtime, + principal); + if (ret) + return ret; + } + + if (pac->server_checksum->buffersize < 4 || + pac->privsvr_checksum->buffersize < 4) + return EINVAL; /* * in the service case, clean out data option of the privsvr and * server checksum before checking the checksum. */ + if (server != NULL) { krb5_data *copy; @@ -897,6 +922,20 @@ krb5_pac_verify(krb5_context context, privsvr); if (ret) return ret; + + if (pac->ticket_sign_data.length != 0) { + if (pac->ticket_checksum == NULL) { + krb5_set_error_message(context, EINVAL, + "PAC missing ticket checksum"); + return EINVAL; + } + + ret = verify_checksum(context, pac->ticket_checksum, &pac->data, + pac->ticket_sign_data.data, + pac->ticket_sign_data.length, privsvr); + if (ret) + return ret; + } } return 0; @@ -965,13 +1004,14 @@ _krb5_pac_sign(krb5_context context, krb5_principal principal, const krb5_keyblock *server_key, const krb5_keyblock *priv_key, + uint16_t rodc_id, krb5_data *data) { krb5_error_code ret; krb5_storage *sp = NULL, *spdata = NULL; uint32_t end; size_t server_size, priv_size; - uint32_t server_offset = 0, priv_offset = 0; + uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0; uint32_t server_cksumtype = 0, priv_cksumtype = 0; int num = 0; size_t i; @@ -985,9 +1025,9 @@ _krb5_pac_sign(krb5_context context, p->server_checksum = &p->pac->buffers[i]; } if (p->server_checksum != &p->pac->buffers[i]) { - ret = EINVAL; + ret = KRB5KDC_ERR_BADOPTION; krb5_set_error_message(context, ret, - N_("PAC have two server checksums", "")); + N_("PAC has multiple server checksums", "")); goto out; } } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) { @@ -995,9 +1035,9 @@ _krb5_pac_sign(krb5_context context, p->privsvr_checksum = &p->pac->buffers[i]; } if (p->privsvr_checksum != &p->pac->buffers[i]) { - ret = EINVAL; + ret = KRB5KDC_ERR_BADOPTION; krb5_set_error_message(context, ret, - N_("PAC have two KDC checksums", "")); + N_("PAC has multiple KDC checksums", "")); goto out; } } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { @@ -1005,9 +1045,19 @@ _krb5_pac_sign(krb5_context context, p->logon_name = &p->pac->buffers[i]; } if (p->logon_name != &p->pac->buffers[i]) { - ret = EINVAL; + ret = KRB5KDC_ERR_BADOPTION; + krb5_set_error_message(context, ret, + N_("PAC has multiple logon names", "")); + goto out; + } + } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) { + if (p->ticket_checksum == NULL) { + p->ticket_checksum = &p->pac->buffers[i]; + } + if (p->ticket_checksum != &p->pac->buffers[i]) { + ret = KRB5KDC_ERR_BADOPTION; krb5_set_error_message(context, ret, - N_("PAC have two logon names", "")); + N_("PAC has multiple ticket checksums", "")); goto out; } } @@ -1019,6 +1069,8 @@ _krb5_pac_sign(krb5_context context, num++; if (p->privsvr_checksum == NULL) num++; + if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL) + num++; if (num) { void *ptr; @@ -1044,6 +1096,11 @@ _krb5_pac_sign(krb5_context context, memset(p->privsvr_checksum, 0, sizeof(*p->privsvr_checksum)); p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM; } + if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL) { + p->ticket_checksum = &p->pac->buffers[p->pac->numbuffers++]; + memset(p->ticket_checksum, 0, sizeof(*p->privsvr_checksum)); + p->ticket_checksum->type = PAC_TICKET_CHECKSUM; + } } /* Calculate LOGON NAME */ @@ -1055,6 +1112,7 @@ _krb5_pac_sign(krb5_context context, ret = pac_checksum(context, server_key, &server_cksumtype, &server_size); if (ret) goto out; + ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size); if (ret) goto out; @@ -1095,10 +1153,24 @@ _krb5_pac_sign(krb5_context context, priv_offset = end + 4; CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out); CHECK(ret, fill_zeros(context, spdata, priv_size), out); + if (rodc_id != 0) { + len += sizeof(rodc_id); + CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out); + } + } else if (p->ticket_sign_data.length != 0 && + p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) { + len = priv_size + 4; + ticket_offset = end + 4; + CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out); + CHECK(ret, fill_zeros(context, spdata, priv_size), out); + if (rodc_id != 0) { + len += sizeof(rodc_id); + CHECK(ret, krb5_store_uint16(spdata, rodc_id), out); + } } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { len = krb5_storage_write(spdata, logon.data, logon.length); if (logon.length != len) { - ret = EINVAL; + ret = KRB5KDC_ERR_BADOPTION; goto out; } } else { @@ -1156,6 +1228,16 @@ _krb5_pac_sign(krb5_context context, } /* sign */ + if (p->ticket_sign_data.length) { + ret = create_checksum(context, priv_key, priv_cksumtype, + p->ticket_sign_data.data, + p->ticket_sign_data.length, + (char *)d.data + ticket_offset, priv_size); + if (ret) { + krb5_data_free(&d); + goto out; + } + } ret = create_checksum(context, server_key, server_cksumtype, d.data, d.length, (char *)d.data + server_offset, server_size); @@ -1171,6 +1253,32 @@ _krb5_pac_sign(krb5_context context, goto out; } + if (rodc_id != 0) { + krb5_data rd; + krb5_storage *rs = krb5_storage_emem(); + if (rs == NULL) { + krb5_data_free(&d); + ret = krb5_enomem(context); + goto out; + } + krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE); + ret = krb5_store_uint16(rs, rodc_id); + if (ret) { + krb5_storage_free(rs); + krb5_data_free(&d); + goto out; + } + ret = krb5_storage_to_data(rs, &rd); + krb5_storage_free(rs); + if (ret) { + krb5_data_free(&d); + goto out; + } + heim_assert(rd.length == sizeof(rodc_id), "invalid length"); + memcpy((char *)d.data + priv_offset + priv_size, rd.data, rd.length); + krb5_data_free(&rd); + } + /* done */ *data = d; @@ -1187,3 +1295,221 @@ out: krb5_storage_free(spdata); return ret; } + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_pac_get_kdc_checksum_info(krb5_context context, + krb5_pac pac, + krb5_cksumtype *cstype, + uint16_t *rodc_id) +{ + krb5_error_code ret; + krb5_storage *sp = NULL; + const struct PAC_INFO_BUFFER *sig; + size_t cksumsize, prefix; + uint32_t type = 0; + + *cstype = 0; + *rodc_id = 0; + + sig = pac->privsvr_checksum; + if (sig == NULL) { + krb5_set_error_message(context, KRB5KDC_ERR_BADOPTION, + "PAC missing kdc checksum"); + return KRB5KDC_ERR_BADOPTION; + } + + sp = krb5_storage_from_mem((char *)pac->data.data + sig->offset_lo, + sig->buffersize); + if (sp == NULL) + return krb5_enomem(context); + + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + ret = krb5_ret_uint32(sp, &type); + if (ret) + goto out; + + ret = krb5_checksumsize(context, type, &cksumsize); + if (ret) + goto out; + + prefix = krb5_storage_seek(sp, 0, SEEK_CUR); + + if ((sig->buffersize - prefix) >= cksumsize + 2) { + krb5_storage_seek(sp, cksumsize, SEEK_CUR); + ret = krb5_ret_uint16(sp, rodc_id); + if (ret) + goto out; + } + + *cstype = type; + +out: + krb5_storage_free(sp); + + return ret; +} + +static unsigned char single_zero = '\0'; +static krb5_data single_zero_pac = { 1, &single_zero }; + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kdc_pac_ticket_parse(krb5_context context, + EncTicketPart *tkt, + krb5_boolean *signedticket, + krb5_pac *ppac) +{ + AuthorizationData *ad = tkt->authorization_data; + krb5_boolean pac_found = FALSE; + krb5_pac pac = NULL; + unsigned i, j; + size_t len = 0; + krb5_error_code ret; + + *signedticket = FALSE; + *ppac = NULL; + + if (ad == NULL || ad->len == 0) + return 0; + + for (i = 0; i < ad->len; i++) { + AuthorizationData child; + + if (ad->val[i].ad_type == KRB5_AUTHDATA_WIN2K_PAC) + return KRB5KDC_ERR_BADOPTION; + + if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) + continue; + + ret = decode_AuthorizationData(ad->val[i].ad_data.data, + ad->val[i].ad_data.length, + &child, + NULL); + if (ret) { + krb5_set_error_message(context, ret, "Failed to decode " + "AD-IF-RELEVANT with %d", ret); + return ret; + } + + for (j = 0; j < child.len; j++) { + if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { + krb5_data adifr_data = ad->val[i].ad_data; + krb5_data pac_data = child.val[j].ad_data; + krb5_data recoded_adifr; + + if (pac_found) { + free_AuthorizationData(&child); + return KRB5KDC_ERR_BADOPTION; + } + pac_found = TRUE; + + ret = krb5_pac_parse(context, + pac_data.data, + pac_data.length, + &pac); + if (ret) { + free_AuthorizationData(&child); + return ret; + } + + if (pac->ticket_checksum == NULL) { + free_AuthorizationData(&child); + *ppac = pac; + continue; + } + + /* + * Encode the ticket with the PAC replaced with a single zero + * byte, to be used as input data to the ticket signature. + */ + + child.val[j].ad_data = single_zero_pac; + + ASN1_MALLOC_ENCODE(AuthorizationData, recoded_adifr.data, + recoded_adifr.length, &child, &len, ret); + if (recoded_adifr.length != len) + krb5_abortx(context, "Internal error in ASN.1 encoder"); + + child.val[j].ad_data = pac_data; + free_AuthorizationData(&child); + + if (ret) { + krb5_pac_free(context, pac); + return ret; + } + + ad->val[i].ad_data = recoded_adifr; + + ASN1_MALLOC_ENCODE(EncTicketPart, + pac->ticket_sign_data.data, + pac->ticket_sign_data.length, tkt, &len, + ret); + if(pac->ticket_sign_data.length != len) + krb5_abortx(context, "Internal error in ASN.1 encoder"); + + ad->val[i].ad_data = adifr_data; + krb5_data_free(&recoded_adifr); + + if (ret) { + krb5_pac_free(context, pac); + return ret; + } + + *signedticket = TRUE; + *ppac = pac; + } + } + free_AuthorizationData(&child); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kdc_pac_sign_ticket(krb5_context context, + const krb5_pac pac, + krb5_principal client, + const krb5_keyblock *server_key, + const krb5_keyblock *kdc_key, + uint16_t rodc_id, + krb5_boolean add_ticket_sig, + EncTicketPart *tkt) +{ + krb5_error_code ret; + krb5_data tkt_data; + krb5_data rspac; + + krb5_data_zero(&rspac); + krb5_data_zero(&tkt_data); + + krb5_data_free(&pac->ticket_sign_data); + + if (add_ticket_sig) { + size_t len = 0; + + ret = _kdc_tkt_insert_pac(context, tkt, &single_zero_pac); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(EncTicketPart, tkt_data.data, tkt_data.length, + tkt, &len, ret); + if(tkt_data.length != len) + krb5_abortx(context, "Internal error in ASN.1 encoder"); + if (ret) + return ret; + + ret = remove_AuthorizationData(tkt->authorization_data, 0); + if (ret) { + krb5_data_free(&tkt_data); + return ret; + } + + pac->ticket_sign_data = tkt_data; + } + + ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key, + kdc_key, rodc_id, &rspac); + if (ret) + return ret; + + return _kdc_tkt_insert_pac(context, tkt, &rspac); +} diff --git a/source4/heimdal/lib/krb5/version-script.map b/source4/heimdal/lib/krb5/version-script.map index b95ba92f4f6..e04e02aace9 100644 --- a/source4/heimdal/lib/krb5/version-script.map +++ b/source4/heimdal/lib/krb5/version-script.map @@ -751,6 +751,11 @@ HEIMDAL_KRB5_2.0 { _krb5_get_host_realm_int; _krb5_get_int; _krb5_pac_sign; + _krb5_kdc_pac_sign_ticket; + _krb5_kdc_pac_ticket_parse; + _krb5_pac_get_kdc_checksum_info; + _kdc_tkt_insert_pac; + _kdc_tkt_add_if_relevant_ad; _krb5_parse_moduli; _krb5_pk_kdf; _krb5_pk_load_id; diff --git a/source4/heimdal_build/wscript_build b/source4/heimdal_build/wscript_build index 9904b245218..f151788dcfd 100644 --- a/source4/heimdal_build/wscript_build +++ b/source4/heimdal_build/wscript_build @@ -606,7 +606,7 @@ if not bld.CONFIG_SET("USING_SYSTEM_KRB5"): KRB5_SOURCE = [os.path.join('lib/krb5/', x) for x in to_list( '''acache.c add_et_list.c addr_families.c appdefault.c - asn1_glue.c auth_context.c + asn1_glue.c auth_context.c authdata.c build_ap_req.c build_auth.c cache.c changepw.c codec.c config_file.c constants.c convert_creds.c diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 187cdd18132..7aba1c6ce55 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -788,7 +788,7 @@ planoldpythontestsuite("ad_dc:local", "samba.tests.gpo", extra_args=['-U"$USERNA planoldpythontestsuite("ad_dc:local", "samba.tests.dckeytab", extra_args=['-U"$USERNAME%$PASSWORD"']) have_fast_support = int('SAMBA_USES_MITKDC' in config_hash) -tkt_sig_support = 0 +tkt_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash) planoldpythontestsuite("none", "samba.tests.krb5.kcrypto") planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.simple_tests", environ={'SERVICE_USERNAME':'$SERVER', -- 2.25.1 From 6718286ede5d0a95eb628210802d545fae55a6ae Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Sun, 19 Sep 2021 15:04:14 +0300 Subject: [PATCH 125/162] krb5: allow NULL parameter to krb5_pac_free() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Cherry-picked from Heimdal commit b295167208a96e68515902138f6ce93972892ec5] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 2d09de5c41e729bccc2d7949d8a3568a95e80e76) --- source4/heimdal/kdc/krb5tgs.c | 3 +-- source4/heimdal/lib/krb5/pac.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index 3b35b828402..d0483a3903b 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -2074,8 +2074,7 @@ out: free_EncTicketPart(&adtkt); - if (mspac) - krb5_pac_free(context, mspac); + krb5_pac_free(context, mspac); return ret; } diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index eec1e84c7bd..18f385fac1f 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -435,6 +435,8 @@ krb5_pac_get_types(krb5_context context, KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_pac_free(krb5_context context, krb5_pac pac) { + if (pac == NULL) + return; krb5_data_free(&pac->data); krb5_data_free(&pac->ticket_sign_data); free(pac->pac); -- 2.25.1 From 78fa18ee101a2727c0c522aed1e68628878828f9 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Sun, 19 Sep 2021 15:16:58 +0300 Subject: [PATCH 126/162] krb5: rework PAC validation loop Avoid allocating the PAC on error. Closes: #836 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Cherry-picked from Heimdal commit 6df8be5091363a1c9a9165465ab8292f817bec81] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 2773379603a5a625c5d1c6e62f29c442942ff570) --- source4/heimdal/lib/krb5/pac.c | 132 +++++++++++++++++---------------- 1 file changed, 69 insertions(+), 63 deletions(-) diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index 18f385fac1f..922a8710eda 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -1362,11 +1362,10 @@ _krb5_kdc_pac_ticket_parse(krb5_context context, krb5_pac *ppac) { AuthorizationData *ad = tkt->authorization_data; - krb5_boolean pac_found = FALSE; krb5_pac pac = NULL; unsigned i, j; size_t len = 0; - krb5_error_code ret; + krb5_error_code ret = 0; *signedticket = FALSE; *ppac = NULL; @@ -1377,8 +1376,10 @@ _krb5_kdc_pac_ticket_parse(krb5_context context, for (i = 0; i < ad->len; i++) { AuthorizationData child; - if (ad->val[i].ad_type == KRB5_AUTHDATA_WIN2K_PAC) - return KRB5KDC_ERR_BADOPTION; + if (ad->val[i].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { + ret = KRB5KDC_ERR_BADOPTION; + goto out; + } if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) continue; @@ -1390,79 +1391,84 @@ _krb5_kdc_pac_ticket_parse(krb5_context context, if (ret) { krb5_set_error_message(context, ret, "Failed to decode " "AD-IF-RELEVANT with %d", ret); - return ret; + goto out; } for (j = 0; j < child.len; j++) { - if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { - krb5_data adifr_data = ad->val[i].ad_data; - krb5_data pac_data = child.val[j].ad_data; - krb5_data recoded_adifr; - - if (pac_found) { - free_AuthorizationData(&child); - return KRB5KDC_ERR_BADOPTION; - } - pac_found = TRUE; - - ret = krb5_pac_parse(context, - pac_data.data, - pac_data.length, - &pac); - if (ret) { - free_AuthorizationData(&child); - return ret; - } - - if (pac->ticket_checksum == NULL) { - free_AuthorizationData(&child); - *ppac = pac; - continue; - } - - /* - * Encode the ticket with the PAC replaced with a single zero - * byte, to be used as input data to the ticket signature. - */ - - child.val[j].ad_data = single_zero_pac; - - ASN1_MALLOC_ENCODE(AuthorizationData, recoded_adifr.data, - recoded_adifr.length, &child, &len, ret); - if (recoded_adifr.length != len) - krb5_abortx(context, "Internal error in ASN.1 encoder"); - - child.val[j].ad_data = pac_data; + krb5_data adifr_data = ad->val[i].ad_data; + krb5_data pac_data = child.val[j].ad_data; + krb5_data recoded_adifr; + + if (child.val[j].ad_type != KRB5_AUTHDATA_WIN2K_PAC) + continue; + + if (pac != NULL) { + free_AuthorizationData(&child); + ret = KRB5KDC_ERR_BADOPTION; + goto out; + } + + ret = krb5_pac_parse(context, + pac_data.data, + pac_data.length, + &pac); + if (ret) { free_AuthorizationData(&child); + goto out; + } - if (ret) { - krb5_pac_free(context, pac); - return ret; - } + if (pac->ticket_checksum == NULL) + continue; - ad->val[i].ad_data = recoded_adifr; + /* + * Encode the ticket with the PAC replaced with a single zero + * byte, to be used as input data to the ticket signature. + */ - ASN1_MALLOC_ENCODE(EncTicketPart, - pac->ticket_sign_data.data, - pac->ticket_sign_data.length, tkt, &len, - ret); - if(pac->ticket_sign_data.length != len) - krb5_abortx(context, "Internal error in ASN.1 encoder"); + child.val[j].ad_data = single_zero_pac; - ad->val[i].ad_data = adifr_data; - krb5_data_free(&recoded_adifr); + ASN1_MALLOC_ENCODE(AuthorizationData, recoded_adifr.data, + recoded_adifr.length, &child, &len, ret); + if (recoded_adifr.length != len) + krb5_abortx(context, "Internal error in ASN.1 encoder"); - if (ret) { - krb5_pac_free(context, pac); - return ret; - } + child.val[j].ad_data = pac_data; - *signedticket = TRUE; - *ppac = pac; + if (ret) { + free_AuthorizationData(&child); + goto out; } + + ad->val[i].ad_data = recoded_adifr; + + ASN1_MALLOC_ENCODE(EncTicketPart, + pac->ticket_sign_data.data, + pac->ticket_sign_data.length, tkt, &len, + ret); + if (pac->ticket_sign_data.length != len) + krb5_abortx(context, "Internal error in ASN.1 encoder"); + + ad->val[i].ad_data = adifr_data; + krb5_data_free(&recoded_adifr); + + if (ret) { + free_AuthorizationData(&child); + goto out; + } + + *signedticket = TRUE; } free_AuthorizationData(&child); } + +out: + if (ret) { + krb5_pac_free(context, pac); + return ret; + } + + *ppac = pac; + return 0; } -- 2.25.1 From b6e4b6660f4edc0d6ec044f331a5f1c683d073b3 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Fri, 17 Sep 2021 13:57:57 +1000 Subject: [PATCH 127/162] krb5: return KRB5KRB_AP_ERR_INAPP_CKSUM if PAC checksum fails Return KRB5KRB_AP_ERR_INAPP_CKSUM instead of EINVAL when verifying a PAC, if the checksum is absent or unkeyed. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Cherry-picked from Heimdal commit c4b99b48c4b18f30d504b427bc1961d7a71f631e] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit d6a472e953545ec3858ca969c1a4191e4f27ba63) --- source4/heimdal/lib/krb5/pac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index 922a8710eda..3e45125d35e 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -489,13 +489,13 @@ verify_checksum(krb5_context context, } ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length); if (ret != (int)cksum.checksum.length) { - ret = EINVAL; + ret = KRB5KRB_AP_ERR_INAPP_CKSUM; krb5_set_error_message(context, ret, "PAC checksum missing checksum"); goto out; } if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) { - ret = EINVAL; + ret = KRB5KRB_AP_ERR_INAPP_CKSUM; krb5_set_error_message(context, ret, "Checksum type %d not keyed", cksum.cksumtype); goto out; -- 2.25.1 From 59ac0d07c0b44e0b021d401bb4d3b3dd77bba5fd Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Sun, 6 Jan 2019 17:54:58 +1100 Subject: [PATCH 128/162] kdc: only set HDB_F_GET_KRBTGT when requesting TGS principal BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Backported from Heimdal commit f1dd2b818aa0866960945edea02a6bc782ed697c - Removed change to _kdc_find_etype() use_strongest_session_key parameter since Samba's Heimdal version uses different logic ] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit db30b71f79864a20b38a1f812a5df833f3a92de8) --- source4/heimdal/kdc/kerberos5.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 7b17d2539ce..d1fd201113b 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -983,6 +983,7 @@ _kdc_as_rep(krb5_context context, pk_client_params *pkp = NULL; #endif const EncryptionKey *pk_reply_key = NULL; + krb5_boolean is_tgs; memset(&rep, 0, sizeof(rep)); memset(&session_key, 0, sizeof(session_key)); @@ -1033,6 +1034,8 @@ _kdc_as_rep(krb5_context context, kdc_log(context, config, 0, "AS-REQ %s from %s for %s", client_name, from, server_name); + is_tgs = krb5_principal_is_krbtgt(context, server_princ); + /* * */ @@ -1101,7 +1104,7 @@ _kdc_as_rep(krb5_context context, goto out; } ret = _kdc_db_fetch(context, config, server_princ, - HDB_F_GET_SERVER|HDB_F_GET_KRBTGT | flags, + HDB_F_GET_SERVER | flags | (is_tgs ? HDB_F_GET_KRBTGT : 0), NULL, NULL, &server); if(ret == HDB_ERR_NOT_FOUND_HERE) { kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", server_name); -- 2.25.1 From 1c53dc31f20268c71925ef3d5665a4b736a8896b Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Thu, 23 Sep 2021 14:39:35 +1000 Subject: [PATCH 129/162] kdc: use ticket client name when signing PAC The principal in the PAC_LOGON_NAME buffer is expected to match the client name in the ticket. Previously we were setting this to the canonical client name, which would have broken PAC validation if the client did not request name canonicalization BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Backported from Heimdal commit 3b0856cab2b25624deb1f6e0e67637ba96a647ac - Renamed variable to avoid shadowing existing variable ] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 75d1a7cd14b134506061ed64ddb9b99856231d2c) --- source4/heimdal/kdc/kerberos5.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index d1fd201113b..6dc945b134a 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -1716,6 +1716,7 @@ _kdc_as_rep(krb5_context context, krb5_pac p = NULL; krb5_data data; uint16_t rodc_id; + krb5_principal client_pac; ret = _kdc_pac_generate(context, client, pk_reply_key, &p); if (ret) { @@ -1726,12 +1727,21 @@ _kdc_as_rep(krb5_context context, if (p != NULL) { rodc_id = server->entry.kvno >> 16; + /* libkrb5 expects ticket and PAC client names to match */ + ret = _krb5_principalname2krb5_principal(context, &client_pac, + et.cname, et.crealm); + if (ret) { + krb5_pac_free(context, p); + goto out; + } + ret = _krb5_pac_sign(context, p, et.authtime, - client->entry.principal, + client_pac, &skey->key, /* Server key */ &skey->key, /* FIXME: should be krbtgt key */ rodc_id, &data); + krb5_free_principal(context, client_pac); krb5_pac_free(context, p); if (ret) { kdc_log(context, config, 0, "PAC signing failed for -- %s", -- 2.25.1 From 18ba837a32e9371b5872e66b1ad83d1b490cd53d Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Thu, 23 Sep 2021 17:51:51 +1000 Subject: [PATCH 130/162] kdc: correctly generate PAC TGS signature When generating an AS-REQ, the TGS signature was incorrectly generated using the server key, which would fail to validate if the server was not also the TGS. Fix this. Patch from Isaac Bourkis . BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Backported from Heimdal commit e7863e2af922809dad25a2e948e98c408944d551 - Samba's Heimdal version does not have the generate_pac() helper function. - Samba's Heimdal version does not use the 'r' context variable. ] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 91e684f5dcb48b76e6a322c15acb53cbce5c275a) --- source4/heimdal/kdc/kerberos5.c | 49 ++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 6dc945b134a..a131f1af08e 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -948,6 +948,33 @@ _kdc_is_anonymous(krb5_context context, krb5_principal principal) return 1; } +static krb5_error_code +get_local_tgs(krb5_context context, + krb5_kdc_configuration *config, + krb5_const_realm realm, + hdb_entry_ex **krbtgt) +{ + krb5_error_code ret; + krb5_principal tgs_name; + + *krbtgt = NULL; + + ret = krb5_make_principal(context, + &tgs_name, + realm, + KRB5_TGS_NAME, + realm, + NULL); + if (ret) + return ret; + + ret = _kdc_db_fetch(context, config, tgs_name, + HDB_F_GET_KRBTGT, NULL, NULL, krbtgt); + krb5_free_principal(context, tgs_name); + + return ret; +} + /* * */ @@ -984,6 +1011,8 @@ _kdc_as_rep(krb5_context context, #endif const EncryptionKey *pk_reply_key = NULL; krb5_boolean is_tgs; + hdb_entry_ex *krbtgt = NULL; + Key *krbtgt_key = NULL; memset(&rep, 0, sizeof(rep)); memset(&session_key, 0, sizeof(session_key)); @@ -1466,6 +1495,22 @@ _kdc_as_rep(krb5_context context, if(ret) goto out; + /* If server is not krbtgt, fetch local krbtgt key for signing authdata */ + if (is_tgs) { + krbtgt_key = skey; + } else { + ret = get_local_tgs(context, config, server_princ->realm, + &krbtgt); + if (ret) + goto out; + + ret = _kdc_get_preferred_key(context, config, krbtgt, + server_princ->realm, + NULL, &krbtgt_key); + if (ret) + goto out; + } + if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey || (f.request_anonymous && !config->allow_anonymous)) { ret = KRB5KDC_ERR_BADOPTION; @@ -1738,7 +1783,7 @@ _kdc_as_rep(krb5_context context, ret = _krb5_pac_sign(context, p, et.authtime, client_pac, &skey->key, /* Server key */ - &skey->key, /* FIXME: should be krbtgt key */ + &krbtgt_key->key, /* TGS key */ rodc_id, &data); krb5_free_principal(context, client_pac); @@ -1807,6 +1852,8 @@ out: _kdc_free_ent(context, client); if(server) _kdc_free_ent(context, server); + if (krbtgt) + _kdc_free_ent(context, krbtgt); return ret; } -- 2.25.1 From 62171bed64bceac8053e7d35aca244e987d461f1 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 11 Aug 2021 13:27:11 +1200 Subject: [PATCH 131/162] s4/heimdal/lib/krb5/pac.c: Align PAC buffers to match Windows BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 28a5a586c8e9cd155d676dcfcb81a2587ace99d1) --- selftest/knownfail_heimdal_kdc | 1 + source4/heimdal/lib/krb5/pac.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 4ec682c01d0..20eea7f2d7e 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -124,6 +124,7 @@ # # S4U tests # +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_constrained_delegation_old_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_client_checksum diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index 3e45125d35e..6535a9bdcc4 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -62,10 +62,12 @@ struct krb5_pac_data { #define PACTYPE_SIZE 8 #define PAC_INFO_BUFFER_SIZE 16 +#define PAC_LOGON_INFO 1 #define PAC_SERVER_CHECKSUM 6 #define PAC_PRIVSVR_CHECKSUM 7 #define PAC_LOGON_NAME 10 #define PAC_CONSTRAINED_DELEGATION 11 +#define PAC_UPN_DNS_INFO 12 #define PAC_TICKET_CHECKSUM 16 #define CHECK(r,f,l) \ @@ -1184,7 +1186,17 @@ _krb5_pac_sign(krb5_context context, ret = krb5_enomem(context); goto out; } - /* XXX if not aligned, fill_zeros */ + + if (p->pac->buffers[i].type == PAC_LOGON_INFO + || p->pac->buffers[i].type == PAC_UPN_DNS_INFO) + { + uint32_t rounded = (len + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT + * PAC_ALIGNMENT; + uint32_t remaining = rounded - len; + CHECK(ret, fill_zeros(context, spdata, remaining), out); + + len = rounded; + } } /* write header */ -- 2.25.1 From e915ea464fa5af1162fc43f10f5ff4262bd1daa1 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 15:43:41 +1300 Subject: [PATCH 132/162] heimdal: Make _krb5_pac_get_kdc_checksum_info() into a global function This lets us call it from Samba. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 3bdce12789af1e7a7aba56691f184625a432410d) --- source4/heimdal/lib/krb5/pac.c | 8 ++++---- source4/heimdal/lib/krb5/version-script.map | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index 6535a9bdcc4..f6d38178a88 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -1311,10 +1311,10 @@ out: } KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -_krb5_pac_get_kdc_checksum_info(krb5_context context, - krb5_pac pac, - krb5_cksumtype *cstype, - uint16_t *rodc_id) +krb5_pac_get_kdc_checksum_info(krb5_context context, + krb5_pac pac, + krb5_cksumtype *cstype, + uint16_t *rodc_id) { krb5_error_code ret; krb5_storage *sp = NULL; diff --git a/source4/heimdal/lib/krb5/version-script.map b/source4/heimdal/lib/krb5/version-script.map index e04e02aace9..2359001e9da 100644 --- a/source4/heimdal/lib/krb5/version-script.map +++ b/source4/heimdal/lib/krb5/version-script.map @@ -470,6 +470,7 @@ HEIMDAL_KRB5_2.0 { krb5_pac_add_buffer; krb5_pac_free; krb5_pac_get_buffer; + krb5_pac_get_kdc_checksum_info; krb5_pac_get_types; krb5_pac_init; krb5_pac_parse; @@ -753,7 +754,6 @@ HEIMDAL_KRB5_2.0 { _krb5_pac_sign; _krb5_kdc_pac_sign_ticket; _krb5_kdc_pac_ticket_parse; - _krb5_pac_get_kdc_checksum_info; _kdc_tkt_insert_pac; _kdc_tkt_add_if_relevant_ad; _krb5_parse_moduli; -- 2.25.1 From 49eaac8b67d633b4ba76297e5fbbf5330ac9f696 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 16:08:39 +1300 Subject: [PATCH 133/162] s4:kdc: Check ticket signature BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 02fa69c6c73c01d82807be4370e838f3e7c66f35) --- selftest/knownfail_heimdal_kdc | 9 -- source4/kdc/wdc-samba4.c | 270 ++++++++++++++++++++++++++------- 2 files changed, 215 insertions(+), 64 deletions(-) diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 20eea7f2d7e..683dbacb979 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -124,13 +124,8 @@ # # S4U tests # -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_constrained_delegation_old_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_client_checksum -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_service_checksum -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_zeroed_client_checksum -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_zeroed_service_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_existing_delegation_info ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_missing_client_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_a @@ -142,10 +137,6 @@ ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_forwardable ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_empty_allowed # -# RODC tests -# -^samba.tests.krb5.rodc_tests.samba.tests.krb5.rodc_tests.RodcKerberosTests.test_rodc_ticket_signature -# # The lack of KRB5SignedPath means we no longer return # KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case # diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 037db40ce46..589df8a651d 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -23,7 +23,10 @@ #include "includes.h" #include "kdc/kdc-glue.h" +#include "kdc/db-glue.h" #include "kdc/pac-glue.h" +#include "sdb.h" +#include "sdb_hdb.h" /* * Given the right private pointer from hdb_samba4, @@ -94,15 +97,13 @@ static krb5_error_code samba_wdc_get_pac_compat(void *priv, krb5_context context return samba_wdc_get_pac(priv, context, client, NULL, pac); } -/* Resign (and reform, including possibly new groups) a PAC */ - -static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, - const krb5_principal client_principal, - const krb5_principal delegated_proxy_principal, - struct hdb_entry_ex *client, - struct hdb_entry_ex *server, - struct hdb_entry_ex *krbtgt, - krb5_pac *pac) +static krb5_error_code samba_wdc_reget_pac2(krb5_context context, + const krb5_principal delegated_proxy_principal, + struct hdb_entry_ex *client, + struct hdb_entry_ex *server, + struct hdb_entry_ex *krbtgt, + krb5_pac *pac, + krb5_cksumtype ctype) { struct samba_kdc_entry *p = talloc_get_type_abort(server->ctx, @@ -110,15 +111,13 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, struct samba_kdc_entry *krbtgt_skdc_entry = talloc_get_type_abort(krbtgt->ctx, struct samba_kdc_entry); - TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context"); + TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac2 context"); krb5_pac new_pac = NULL; DATA_BLOB *pac_blob = NULL; DATA_BLOB *upn_blob = NULL; DATA_BLOB *deleg_blob = NULL; krb5_error_code ret; NTSTATUS nt_status; - struct PAC_SIGNATURE_DATA *pac_srv_sig; - struct PAC_SIGNATURE_DATA *pac_kdc_sig; bool is_in_db, is_untrusted; size_t num_types = 0; uint32_t *types = NULL; @@ -130,6 +129,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, ssize_t upn_dns_info_idx = -1; ssize_t srv_checksum_idx = -1; ssize_t kdc_checksum_idx = -1; + ssize_t tkt_checksum_idx = -1; if (!mem_ctx) { return ENOMEM; @@ -150,6 +150,71 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, return ret; } + if (delegated_proxy_principal != NULL) { + krb5_enctype etype; + Key *key = NULL; + + if (!is_in_db) { + /* + * The RODC-issued PAC was signed by a KDC entry that we + * don't have a key for. The server signature is not + * trustworthy, since it could have been created by the + * server we got the ticket from. We must not proceed as + * otherwise the ticket signature is unchecked. + */ + talloc_free(mem_ctx); + return HDB_ERR_NOT_FOUND_HERE; + } + + /* Fetch the correct key depending on the checksum type. */ + if (ctype == CKSUMTYPE_HMAC_MD5) { + etype = ENCTYPE_ARCFOUR_HMAC; + } else { + ret = krb5_cksumtype_to_enctype(context, + ctype, + &etype); + if (ret != 0) { + talloc_free(mem_ctx); + return ret; + } + } + ret = hdb_enctype2key(context, &krbtgt->entry, etype, &key); + if (ret != 0) { + return ret; + } + + /* Check the KDC and ticket signatures. */ + ret = krb5_pac_verify(context, + *pac, + 0, + NULL, + NULL, + &key->key); + if (ret != 0) { + DEBUG(1, ("PAC KDC signature failed to verify\n")); + talloc_free(mem_ctx); + return ret; + } + + deleg_blob = talloc_zero(mem_ctx, DATA_BLOB); + if (!deleg_blob) { + talloc_free(mem_ctx); + return ENOMEM; + } + + nt_status = samba_kdc_update_delegation_info_blob(mem_ctx, + context, *pac, + server->entry.principal, + delegated_proxy_principal, + deleg_blob); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("Building PAC failed: %s\n", + nt_errstr(nt_status))); + talloc_free(mem_ctx); + return EINVAL; + } + } + if (is_untrusted) { struct samba_kdc_entry *client_skdc_entry = NULL; @@ -173,52 +238,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, return ENOMEM; } - pac_srv_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA); - if (!pac_srv_sig) { - talloc_free(mem_ctx); - return ENOMEM; - } - - pac_kdc_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA); - if (!pac_kdc_sig) { - talloc_free(mem_ctx); - return ENOMEM; - } - nt_status = samba_kdc_update_pac_blob(mem_ctx, context, krbtgt_skdc_entry->kdc_db_ctx->samdb, *pac, pac_blob, - pac_srv_sig, pac_kdc_sig); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("Building PAC failed: %s\n", - nt_errstr(nt_status))); - talloc_free(mem_ctx); - return EINVAL; - } - - if (is_in_db) { - /* Now check the KDC signature, fetching the correct key based on the enc type */ - ret = kdc_check_pac(context, pac_srv_sig->signature, pac_kdc_sig, krbtgt); - if (ret != 0) { - DEBUG(1, ("PAC KDC signature failed to verify\n")); - talloc_free(mem_ctx); - return ret; - } - } - } - - if (delegated_proxy_principal) { - deleg_blob = talloc_zero(mem_ctx, DATA_BLOB); - if (!deleg_blob) { - talloc_free(mem_ctx); - return ENOMEM; - } - - nt_status = samba_kdc_update_delegation_info_blob(mem_ctx, - context, *pac, - server->entry.principal, - delegated_proxy_principal, - deleg_blob); + NULL, NULL); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Building PAC failed: %s\n", nt_errstr(nt_status))); @@ -308,6 +331,18 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, } kdc_checksum_idx = i; break; + case PAC_TYPE_TICKET_CHECKSUM: + if (tkt_checksum_idx != -1) { + DEBUG(1, ("ticket checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n", + types[i], + tkt_checksum_idx, + i)); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + tkt_checksum_idx = i; + break; default: continue; } @@ -471,6 +506,131 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, return ret; } +/* Resign (and reform, including possibly new groups) a PAC */ + +static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, + const krb5_principal client_principal, + const krb5_principal delegated_proxy_principal, + struct hdb_entry_ex *client, + struct hdb_entry_ex *server, + struct hdb_entry_ex *krbtgt, + krb5_pac *pac) +{ + struct samba_kdc_entry *krbtgt_skdc_entry = + talloc_get_type_abort(krbtgt->ctx, + struct samba_kdc_entry); + krb5_error_code ret; + krb5_cksumtype ctype = CKSUMTYPE_NONE; + struct hdb_entry_ex signing_krbtgt_hdb; + + if (delegated_proxy_principal) { + uint16_t rodc_id; + unsigned int my_krbtgt_number; + + /* + * We're using delegated_proxy_principal for the moment to + * indicate cases where the ticket was encrypted with the server + * key, and not a krbtgt key. This cannot be trusted, so we need + * to find a krbtgt key that signs the PAC in order to trust the + * ticket. + * + * The krbtgt passed in to this function refers to the krbtgt + * used to decrypt the ticket of the server requesting + * S4U2Proxy. + * + * When we implement service ticket renewal, we need to check + * the PAC, and this will need to be updated. + */ + ret = krb5_pac_get_kdc_checksum_info(context, + *pac, + &ctype, + &rodc_id); + if (ret != 0) { + DEBUG(1, ("Failed to get PAC checksum info\n")); + return ret; + } + + /* + * We need to check the KDC and ticket signatures, fetching the + * correct key based on the enctype. + */ + + my_krbtgt_number = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number; + + if (my_krbtgt_number != 0) { + /* + * If we are an RODC, and we are not the KDC that signed + * the evidence ticket, then we need to proxy the + * request. + */ + if (rodc_id != my_krbtgt_number) { + return HDB_ERR_NOT_FOUND_HERE; + } + } else { + /* + * If we are a DC, the ticket may have been signed by a + * different KDC than the one that issued the header + * ticket. + */ + if (rodc_id != krbtgt->entry.kvno >> 16) { + struct sdb_entry_ex signing_krbtgt_sdb; + + /* + * If we didn't sign the ticket, then return an + * error. + */ + if (rodc_id != 0) { + return KRB5KRB_AP_ERR_MODIFIED; + } + + /* + * Fetch our key from the database. To support + * key rollover, we're going to need to try + * multiple keys by trial and error. For now, + * krbtgt keys aren't assumed to change. + */ + ret = samba_kdc_fetch(context, + krbtgt_skdc_entry->kdc_db_ctx, + krbtgt->entry.principal, + SDB_F_GET_KRBTGT | SDB_F_CANON, + 0, + &signing_krbtgt_sdb); + if (ret != 0) { + return ret; + } + + ret = sdb_entry_ex_to_hdb_entry_ex(context, + &signing_krbtgt_sdb, + &signing_krbtgt_hdb); + sdb_free_entry(&signing_krbtgt_sdb); + if (ret != 0) { + return ret; + } + + /* + * Replace the krbtgt entry with our own entry + * for further processing. + */ + krbtgt = &signing_krbtgt_hdb; + } + } + } + + ret = samba_wdc_reget_pac2(context, + delegated_proxy_principal, + client, + server, + krbtgt, + pac, + ctype); + + if (krbtgt == &signing_krbtgt_hdb) { + hdb_free_entry(context, &signing_krbtgt_hdb); + } + + return ret; +} + static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs) { char *nb_name = NULL; -- 2.25.1 From 07585981198226c0e1cb01700e3871f359b60acb Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Sun, 10 Oct 2021 21:55:59 -0500 Subject: [PATCH 134/162] krb5: Fix PAC signature leak affecting KDC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 [jsutton@samba.org Cherry-picked from Heimdal commit 54581d2d52443a9a07ed5980df331f660b397dcf] Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit f6adfefbbb41b9100736134d0f975f1ec0c33c42) --- source4/heimdal/lib/krb5/pac.c | 136 +++++++++++++++------------------ 1 file changed, 61 insertions(+), 75 deletions(-) diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index f6d38178a88..05bcc523080 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -1018,9 +1018,10 @@ _krb5_pac_sign(krb5_context context, uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0; uint32_t server_cksumtype = 0, priv_cksumtype = 0; int num = 0; - size_t i; + size_t i, sz; krb5_data logon, d; + krb5_data_zero(&d); krb5_data_zero(&logon); for (i = 0; i < p->pac->numbuffers; i++) { @@ -1080,8 +1081,10 @@ _krb5_pac_sign(krb5_context context, void *ptr; ptr = realloc(p->pac, sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (p->pac->numbuffers + num - 1))); - if (ptr == NULL) - return krb5_enomem(context); + if (ptr == NULL) { + ret = krb5_enomem(context); + goto out; + } p->pac = ptr; @@ -1109,30 +1112,33 @@ _krb5_pac_sign(krb5_context context, /* Calculate LOGON NAME */ ret = build_logon_name(context, authtime, principal, &logon); - if (ret) - goto out; /* Set lengths for checksum */ - ret = pac_checksum(context, server_key, &server_cksumtype, &server_size); - if (ret) - goto out; + if (ret == 0) + ret = pac_checksum(context, server_key, &server_cksumtype, &server_size); - ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size); - if (ret) - goto out; + if (ret == 0) + ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size); /* Encode PAC */ - sp = krb5_storage_emem(); - if (sp == NULL) - return krb5_enomem(context); - - krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + if (ret == 0) { + sp = krb5_storage_emem(); + if (sp == NULL) + ret = krb5_enomem(context); + } - spdata = krb5_storage_emem(); - if (spdata == NULL) { - krb5_storage_free(sp); - return krb5_enomem(context); + if (ret == 0) { + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + spdata = krb5_storage_emem(); + if (spdata == NULL) { + krb5_storage_free(sp); + ret = krb5_enomem(context); + } } + + if (ret) + goto out; + krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out); @@ -1222,77 +1228,56 @@ _krb5_pac_sign(krb5_context context, /* assert (server_offset != 0 && priv_offset != 0); */ /* export PAC */ - ret = krb5_storage_to_data(spdata, &d); - if (ret) { - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto out; - } - ret = krb5_storage_write(sp, d.data, d.length); - if (ret != (int)d.length) { - krb5_data_free(&d); - ret = krb5_enomem(context); - goto out; + if (ret == 0) + ret = krb5_storage_to_data(spdata, &d); + if (ret == 0) { + sz = krb5_storage_write(sp, d.data, d.length); + if (sz != d.length) { + krb5_data_free(&d); + ret = krb5_enomem(context); + goto out; + } } krb5_data_free(&d); - ret = krb5_storage_to_data(sp, &d); - if (ret) { - ret = krb5_enomem(context); - goto out; - } + if (ret == 0) + ret = krb5_storage_to_data(sp, &d); /* sign */ - if (p->ticket_sign_data.length) { + if (ret == 0 && p->ticket_sign_data.length) ret = create_checksum(context, priv_key, priv_cksumtype, p->ticket_sign_data.data, p->ticket_sign_data.length, (char *)d.data + ticket_offset, priv_size); - if (ret) { - krb5_data_free(&d); - goto out; - } - } - ret = create_checksum(context, server_key, server_cksumtype, - d.data, d.length, - (char *)d.data + server_offset, server_size); - if (ret) { - krb5_data_free(&d); - goto out; - } - ret = create_checksum(context, priv_key, priv_cksumtype, - (char *)d.data + server_offset, server_size, - (char *)d.data + priv_offset, priv_size); - if (ret) { - krb5_data_free(&d); - goto out; - } - - if (rodc_id != 0) { + if (ret == 0) + ret = create_checksum(context, server_key, server_cksumtype, + d.data, d.length, + (char *)d.data + server_offset, server_size); + if (ret == 0) + ret = create_checksum(context, priv_key, priv_cksumtype, + (char *)d.data + server_offset, server_size, + (char *)d.data + priv_offset, priv_size); + if (ret == 0 && rodc_id != 0) { krb5_data rd; krb5_storage *rs = krb5_storage_emem(); - if (rs == NULL) { - krb5_data_free(&d); + if (rs == NULL) ret = krb5_enomem(context); - goto out; - } krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE); - ret = krb5_store_uint16(rs, rodc_id); - if (ret) { - krb5_storage_free(rs); - krb5_data_free(&d); - goto out; - } - ret = krb5_storage_to_data(rs, &rd); + if (ret == 0) + ret = krb5_store_uint16(rs, rodc_id); + if (ret == 0) + ret = krb5_storage_to_data(rs, &rd); krb5_storage_free(rs); - if (ret) { - krb5_data_free(&d); + if (ret) goto out; - } heim_assert(rd.length == sizeof(rodc_id), "invalid length"); memcpy((char *)d.data + priv_offset + priv_size, rd.data, rd.length); krb5_data_free(&rd); } + if (ret) + goto out; + /* done */ *data = d; @@ -1302,6 +1287,7 @@ _krb5_pac_sign(krb5_context context, return 0; out: + krb5_data_free(&d); krb5_data_free(&logon); if (sp) krb5_storage_free(sp); @@ -1528,8 +1514,8 @@ _krb5_kdc_pac_sign_ticket(krb5_context context, ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key, kdc_key, rodc_id, &rspac); - if (ret) - return ret; - - return _kdc_tkt_insert_pac(context, tkt, &rspac); + if (ret == 0) + ret = _kdc_tkt_insert_pac(context, tkt, &rspac); + krb5_data_free(&rspac); + return ret; } -- 2.25.1 From 2ec564e67fe132854322e452529a4c281b843759 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 15 Oct 2021 13:09:20 +1300 Subject: [PATCH 135/162] selftest/dbcheck: Fix up RODC one-way links (use correct dbcheck rule) The previous commit was correct on intention, but it was not noticed as there is a race, that the incorrect rule was appended to. These links are removed by remove_plausible_deleted_DN_links not fix_all_old_dn_string_component_mismatch BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andrew Bartlett Reviewed-by: Joseph Sutton Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Fri Oct 15 10:00:47 UTC 2021 on sn-devel-184 (cherry picked from commit a7ad665e65f0701eb75cac5bc10a366ccd9689f4) --- testprogs/blackbox/dbcheck.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testprogs/blackbox/dbcheck.sh b/testprogs/blackbox/dbcheck.sh index e2ba987e2de..5462441005e 100755 --- a/testprogs/blackbox/dbcheck.sh +++ b/testprogs/blackbox/dbcheck.sh @@ -19,12 +19,12 @@ dbcheck() { # This list of attributes can be freely extended dbcheck_fix_one_way_links() { - $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes fix_all_old_dn_string_component_mismatch --attrs="lastKnownParent defaultObjectCategory fromServer rIDSetReferences msDS-RevealOnDemandGroup msDS-NeverRevealGroup" --cross-ncs $ARGS + $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes fix_all_old_dn_string_component_mismatch --attrs="lastKnownParent defaultObjectCategory fromServer rIDSetReferences" --cross-ncs $ARGS } # This list of attributes can be freely extended dbcheck_fix_stale_links() { - $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes remove_plausible_deleted_DN_links --attrs="member msDS-NC-Replica-Locations msDS-NC-RO-Replica-Locations" --cross-ncs $ARGS + $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes remove_plausible_deleted_DN_links --attrs="member msDS-NC-Replica-Locations msDS-NC-RO-Replica-Locations msDS-RevealOnDemandGroup msDS-NeverRevealGroup" --cross-ncs $ARGS } # This list of attributes can be freely extended -- 2.25.1 From 9c991d900f691c62b16f40a47a3048e3b78b6cf0 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 15 Oct 2021 12:12:30 +1300 Subject: [PATCH 136/162] heimdal:kdc: Fix ticket signing without a PAC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit d23d8e859357b0fac4d1f4a49f1dce6cf60d6216) --- source4/heimdal/kdc/krb5tgs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index d0483a3903b..2de3b099199 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -695,10 +695,12 @@ tgs_make_reply(krb5_context context, } /* The PAC should be the last change to the ticket. */ - ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey, - krbtgtkey, rodc_id, add_ticket_sig, &et); + if (mspac != NULL) { + ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey, + krbtgtkey, rodc_id, add_ticket_sig, &et); if (ret) goto out; + } /* It is somewhat unclear where the etype in the following encryption should come from. What we have is a session -- 2.25.1 From 6f18441e7541276cd0f4f686a1b985b058ded805 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 15 Oct 2021 14:26:40 +1300 Subject: [PATCH 137/162] tests/krb5: Allow get_tgt() to request including or omitting a PAC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit e086c6193f6da6fcb5d0bcada2199e9bc7ad25f5) --- python/samba/tests/krb5/kdc_base_test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 87160f675ae..1fc15315b0b 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1306,9 +1306,9 @@ class KDCBaseTest(RawKerberosTest): def get_tgt(self, creds, to_rodc=False, kdc_options=None, expected_flags=None, unexpected_flags=None, - fresh=False): + pac_request=True, expect_pac=True, fresh=False): user_name = creds.get_username() - cache_key = (user_name, to_rodc, kdc_options) + cache_key = (user_name, to_rodc, kdc_options, pac_request) if not fresh: tgt = self.tkt_cache.get(cache_key) @@ -1363,7 +1363,7 @@ class KDCBaseTest(RawKerberosTest): kdc_options=kdc_options, preauth_key=None, ticket_decryption_key=ticket_decryption_key, - pac_request=True, + pac_request=pac_request, pac_options=pac_options, to_rodc=to_rodc) self.check_pre_authentication(rep) @@ -1405,8 +1405,9 @@ class KDCBaseTest(RawKerberosTest): kdc_options=kdc_options, preauth_key=preauth_key, ticket_decryption_key=ticket_decryption_key, - pac_request=True, + pac_request=pac_request, pac_options=pac_options, + expect_pac=expect_pac, to_rodc=to_rodc) self.check_as_reply(rep) -- 2.25.1 From 27066e1d739ac340a19d7fcf2c8037a9dd499c78 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 15 Oct 2021 14:27:15 +1300 Subject: [PATCH 138/162] tests/krb5: Allow specifying whether to expect a PAC with _test_as_exchange() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 0dc69c1327f72384628a869a00482f6528b8671b) --- python/samba/tests/krb5/raw_testcase.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index e008223eb23..29dc5f397b6 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -3530,6 +3530,7 @@ class RawKerberosTest(TestCaseInTempDir): ticket_decryption_key=None, pac_request=None, pac_options=None, + expect_pac=True, to_rodc=False): def _generate_padata_copy(_kdc_exchange_dict, @@ -3569,6 +3570,7 @@ class RawKerberosTest(TestCaseInTempDir): kdc_options=str(kdc_options), pac_request=pac_request, pac_options=pac_options, + expect_pac=expect_pac, to_rodc=to_rodc) rep = self._generic_kdc_exchange(kdc_exchange_dict, -- 2.25.1 From 27ef24fa2096911c0b765f6b7f2548deb7ac8dda Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 15 Oct 2021 14:27:25 +1300 Subject: [PATCH 139/162] tests/krb5: Add method to get the PAC from a ticket BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (cherry picked from commit 288355896a2b6f460c42559ec46ff980ab57782e) --- python/samba/tests/krb5/raw_testcase.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 29dc5f397b6..0790ac13f99 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -3447,6 +3447,15 @@ class RawKerberosTest(TestCaseInTempDir): _, pac = self.replace_pac(auth_data, None, expect_pac) return pac + def get_ticket_pac(self, ticket, expect_pac=True): + auth_data = ticket.ticket_private.get('authorization-data') + if expect_pac: + self.assertIsNotNone(auth_data) + elif auth_data is None: + return None + + return self.get_pac(auth_data, expect_pac=expect_pac) + def get_krbtgt_checksum_key(self): krbtgt_creds = self.get_krbtgt_creds() krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) -- 2.25.1 From 4a8278b602d609ce0151b9a1d243a5ed3fdd27e0 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 15 Oct 2021 14:29:26 +1300 Subject: [PATCH 140/162] tests/krb5: Add tests for requesting a service ticket without a PAC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Sun Oct 17 23:40:33 UTC 2021 on sn-devel-184 [abartlet@samba.org backported from commit 9d3a691920205f8a9dc05d0e173e25e6a335f139 as the MIT KDC 1.16 seen on the reference Ubuntu 18.04 does not fail test_remove_pac] --- python/samba/tests/krb5/kdc_tgs_tests.py | 120 +++++++++++++++++++++++ selftest/knownfail_heimdal_kdc | 5 + selftest/knownfail_mit_kdc | 4 + 3 files changed, 129 insertions(+) diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py index 3075cc6b0a9..9d846a2c3ad 100755 --- a/python/samba/tests/krb5/kdc_tgs_tests.py +++ b/python/samba/tests/krb5/kdc_tgs_tests.py @@ -23,15 +23,18 @@ import os sys.path.insert(0, "bin/python") os.environ["PYTHONUNBUFFERED"] = "1" +import samba.tests.krb5.kcrypto as kcrypto from samba.tests.krb5.kdc_base_test import KDCBaseTest from samba.tests.krb5.rfc4120_constants import ( AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5, KRB_ERROR, + KRB_TGS_REP, KDC_ERR_BADMATCH, NT_PRINCIPAL, NT_SRV_INST, ) +import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1 global_asn1_print = False global_hexdump = False @@ -209,6 +212,123 @@ class KdcTgsTests(KDCBaseTest): pac_data.account_sid, "rep = {%s},%s" % (rep, pac_data)) + def _make_tgs_request(self, client_creds, service_creds, tgt, + expect_pac=True): + client_account = client_creds.get_username() + cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=[client_account]) + + service_account = service_creds.get_username() + sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=[service_account]) + + realm = service_creds.get_realm() + + expected_crealm = realm + expected_cname = cname + expected_srealm = realm + expected_sname = sname + + expected_supported_etypes = service_creds.tgs_supported_enctypes + + etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) + + kdc_options = str(krb5_asn1.KDCOptions('canonicalize')) + + target_decryption_key = self.TicketDecryptionKey_from_creds( + service_creds) + + authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256) + + kdc_exchange_dict = self.tgs_exchange_dict( + expected_crealm=expected_crealm, + expected_cname=expected_cname, + expected_srealm=expected_srealm, + expected_sname=expected_sname, + expected_supported_etypes=expected_supported_etypes, + ticket_decryption_key=target_decryption_key, + check_rep_fn=self.generic_check_kdc_rep, + check_kdc_private_fn=self.generic_check_kdc_private, + expected_error_mode=0, + tgt=tgt, + authenticator_subkey=authenticator_subkey, + kdc_options=kdc_options, + expect_pac=expect_pac) + + rep = self._generic_kdc_exchange(kdc_exchange_dict, + cname=cname, + realm=realm, + sname=sname, + etypes=etypes) + self.check_reply(rep, KRB_TGS_REP) + + return kdc_exchange_dict['rep_ticket_creds'] + + def test_request_no_pac(self): + client_creds = self.get_client_creds() + service_creds = self.get_service_creds() + + tgt = self.get_tgt(client_creds, pac_request=False, + expect_pac=False) + + pac = self.get_ticket_pac(tgt, expect_pac=False) + self.assertIsNone(pac) + + ticket = self._make_tgs_request(client_creds, service_creds, tgt, + expect_pac=False) + + pac = self.get_ticket_pac(ticket, expect_pac=False) + self.assertIsNone(pac) + + def test_client_no_auth_data_required(self): + client_creds = self.get_cached_creds( + machine_account=False, + opts={'no_auth_data_required': True}) + service_creds = self.get_service_creds() + + tgt = self.get_tgt(client_creds) + + pac = self.get_ticket_pac(tgt) + self.assertIsNotNone(pac) + + ticket = self._make_tgs_request(client_creds, service_creds, tgt) + + pac = self.get_ticket_pac(ticket) + self.assertIsNotNone(pac) + + def test_service_no_auth_data_required(self): + client_creds = self.get_client_creds() + service_creds = self.get_cached_creds( + machine_account=True, + opts={'no_auth_data_required': True}) + + tgt = self.get_tgt(client_creds) + + pac = self.get_ticket_pac(tgt) + self.assertIsNotNone(pac) + + ticket = self._make_tgs_request(client_creds, service_creds, tgt, + expect_pac=False) + + pac = self.get_ticket_pac(ticket, expect_pac=False) + self.assertIsNone(pac) + + def test_remove_pac(self): + client_creds = self.get_client_creds() + service_creds = self.get_service_creds() + + tgt = self.modified_ticket(self.get_tgt(client_creds), + exclude_pac=True) + + pac = self.get_ticket_pac(tgt, expect_pac=False) + self.assertIsNone(pac) + + ticket = self._make_tgs_request(client_creds, service_creds, tgt, + expect_pac=False) + + pac = self.get_ticket_pac(ticket, expect_pac=False) + self.assertIsNone(pac) + if __name__ == "__main__": global_asn1_print = False diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 683dbacb979..32cfa2afa88 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -141,3 +141,8 @@ # KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case # ^samba4.krb5.kdc with machine account.as-req-pac-request.fl2000dc:local +# +# TGS tests +# +^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_client_no_auth_data_required +^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_service_no_auth_data_required diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc index 09efbc7b590..00f652db14a 100644 --- a/selftest/knownfail_mit_kdc +++ b/selftest/knownfail_mit_kdc @@ -276,6 +276,10 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_ldap_service_ticket\(ad_dc\) ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_get_ticket_for_host_service_of_machine_account\(ad_dc\) # +^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_client_no_auth_data_required\(ad_dc\) +^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac\(ad_dc\) +^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_service_no_auth_data_required\(ad_dc\) +# # MIT currently fails the following MS-KILE tests. # ^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_1_3 -- 2.25.1 From 4c7ce74f0425f7d32689f419b7c6f360a638eafe Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 18 Oct 2021 15:21:50 +1300 Subject: [PATCH 141/162] kdc: Remove UF_NO_AUTH_DATA_REQUIRED from client principals Tests against Windows 2019 show that UF_NO_AUTH_DATA_REQUIRED applies to services only, not to clients. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14871 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher [abartlet@samba.org backported from commit 92e8ce18a79e88c9b961dc20e39436c4cf653013 as there was a knownfail conflict with the test_remove_pac case which succeeds on this branch] --- selftest/knownfail_heimdal_kdc | 1 - selftest/knownfail_mit_kdc | 1 - source4/kdc/mit_samba.c | 7 ------- source4/kdc/pac-glue.c | 5 ----- 4 files changed, 14 deletions(-) diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 32cfa2afa88..4d058bad3da 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -144,5 +144,4 @@ # # TGS tests # -^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_client_no_auth_data_required ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_service_no_auth_data_required diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc index 00f652db14a..0f845fb9b1c 100644 --- a/selftest/knownfail_mit_kdc +++ b/selftest/knownfail_mit_kdc @@ -276,7 +276,6 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_ldap_service_ticket\(ad_dc\) ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_get_ticket_for_host_service_of_machine_account\(ad_dc\) # -^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_client_no_auth_data_required\(ad_dc\) ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac\(ad_dc\) ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_service_no_auth_data_required\(ad_dc\) # diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c index 2936fe2d18a..689e14e1c38 100644 --- a/source4/kdc/mit_samba.c +++ b/source4/kdc/mit_samba.c @@ -495,18 +495,11 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx, ssize_t srv_checksum_idx = -1; ssize_t kdc_checksum_idx = -1; krb5_pac new_pac = NULL; - bool ok; if (client != NULL) { client_skdc_entry = talloc_get_type_abort(client->e_data, struct samba_kdc_entry); - - /* The user account may be set not to want the PAC */ - ok = samba_princ_needs_pac(client_skdc_entry); - if (!ok) { - return EINVAL; - } } if (server == NULL) { diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index 88bcb734fc5..688103d8477 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -651,11 +651,6 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx, } *_upn_info_blob = NULL; - /* The user account may be set not to want the PAC */ - if ( ! samba_princ_needs_pac(p)) { - return NT_STATUS_OK; - } - logon_blob = talloc_zero(mem_ctx, DATA_BLOB); if (logon_blob == NULL) { return NT_STATUS_NO_MEMORY; -- 2.25.1 From 75b847ed5bc06954c16041607744ead5169c60fe Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 18 Oct 2021 16:00:45 +1300 Subject: [PATCH 142/162] kdc: Correctly strip PAC, rather than error on UF_NO_AUTH_DATA_REQUIRED for servers UF_NO_AUTH_DATA_REQUIRED on a server/service account should cause the PAC to be stripped not to given an error if the PAC was still present. Tested against Windows 2019 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14871 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher (cherry picked from commit 031a8287642e3c4b9d0b7c6b51f3b1d79b227542) --- selftest/knownfail_heimdal_kdc | 4 ---- source4/kdc/wdc-samba4.c | 38 +++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 4d058bad3da..683dbacb979 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -141,7 +141,3 @@ # KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case # ^samba4.krb5.kdc with machine account.as-req-pac-request.fl2000dc:local -# -# TGS tests -# -^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_service_no_auth_data_required diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 589df8a651d..ac9d7d51733 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -105,13 +105,15 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, krb5_pac *pac, krb5_cksumtype ctype) { - struct samba_kdc_entry *p = + struct samba_kdc_entry *server_skdc_entry = talloc_get_type_abort(server->ctx, struct samba_kdc_entry); struct samba_kdc_entry *krbtgt_skdc_entry = talloc_get_type_abort(krbtgt->ctx, struct samba_kdc_entry); - TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac2 context"); + TALLOC_CTX *mem_ctx = talloc_named(server_skdc_entry, + 0, + "samba_kdc_reget_pac2 context"); krb5_pac new_pac = NULL; DATA_BLOB *pac_blob = NULL; DATA_BLOB *upn_blob = NULL; @@ -135,12 +137,6 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, return ENOMEM; } - /* The user account may be set not to want the PAC */ - if (!samba_princ_needs_pac(p)) { - talloc_free(mem_ctx); - return EINVAL; - } - /* If the krbtgt was generated by an RODC, and we are not that * RODC, then we need to regenerate the PAC - we can't trust * it */ @@ -373,12 +369,28 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, return EINVAL; } - /* Build an updated PAC */ + /* + * The server account may be set not to want the PAC. + * + * While this is wasteful if the above cacluations were done + * and now thrown away, this is cleaner as we do any ticket + * signature checking etc always. + * + * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the + * time (eg not accepting a ticket from the RODC) we do not + * need to re-generate anything anyway. + */ + if (!samba_princ_needs_pac(server_skdc_entry)) { + ret = 0; + new_pac = NULL; + goto out; + } + + /* Otherwise build an updated PAC */ ret = krb5_pac_init(context, &new_pac); if (ret != 0) { - SAFE_FREE(types); - talloc_free(mem_ctx); - return ret; + new_pac = NULL; + goto out; } for (i = 0;;) { @@ -496,6 +508,8 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, } } +out: + SAFE_FREE(types); /* We now replace the pac */ -- 2.25.1 From 6d63f48a94eb1b181e6cf582e5a0c33bb8fbd8b2 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 18 Oct 2021 16:05:19 +1300 Subject: [PATCH 143/162] tests/krb5: Ensure PAC is not present if expect_pac is false BUG: https://bugzilla.samba.org/show_bug.cgi?id=14871 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit cc3d27596b9e8a8a46e8ba9c3c1a445477d458cf) --- python/samba/tests/krb5/raw_testcase.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 0790ac13f99..0b9fe8e7a04 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -2385,13 +2385,6 @@ class RawKerberosTest(TestCaseInTempDir): self.assertElementPresent(ticket_private, 'authorization-data', expect_empty=not expect_pac) - if expect_pac: - authorization_data = self.getElementValue(ticket_private, - 'authorization-data') - pac_data = self.get_pac(authorization_data) - - self.check_pac_buffers(pac_data, kdc_exchange_dict) - encpart_session_key = None if encpart_private is not None: self.assertElementPresent(encpart_private, 'key') @@ -2493,6 +2486,13 @@ class RawKerberosTest(TestCaseInTempDir): ticket_private=ticket_private, encpart_private=encpart_private) + if ticket_private is not None: + pac_data = self.get_ticket_pac(ticket_creds, expect_pac=expect_pac) + if expect_pac: + self.check_pac_buffers(pac_data, kdc_exchange_dict) + else: + self.assertIsNone(pac_data) + expect_ticket_checksum = kdc_exchange_dict['expect_ticket_checksum'] if expect_ticket_checksum: self.assertIsNotNone(ticket_decryption_key) -- 2.25.1 From 9a453932f2922a626040e86e40d062b54c6644a5 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 18 Oct 2021 16:07:11 +1300 Subject: [PATCH 144/162] tests/krb5: Add tests for constrained delegation to NO_AUTH_DATA_REQUIRED service BUG: https://bugzilla.samba.org/show_bug.cgi?id=14871 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Oct 20 09:22:43 UTC 2021 on sn-devel-184 (cherry picked from commit 83a654a4efd39a6e792a6d49e0ecf586e9bc53ef) --- python/samba/tests/krb5/s4u_tests.py | 107 ++++++++++++++++++++++++++- selftest/knownfail_heimdal_kdc | 8 +- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py index 9a25256081a..bbb7135b55b 100755 --- a/python/samba/tests/krb5/s4u_tests.py +++ b/python/samba/tests/krb5/s4u_tests.py @@ -538,6 +538,8 @@ class S4UKerberosTests(KDCBaseTest): transited_service = f'host/{service1_name}@{service1_realm}' expected_transited_services.append(transited_service) + expect_pac = kdc_dict.pop('expect_pac', True) + kdc_exchange_dict = self.tgs_exchange_dict( expected_crealm=client_realm, expected_cname=client_cname, @@ -557,7 +559,8 @@ class S4UKerberosTests(KDCBaseTest): pac_options=pac_options, expect_edata=expect_edata, expected_proxy_target=expected_proxy_target, - expected_transited_services=expected_transited_services) + expected_transited_services=expected_transited_services, + expect_pac=expect_pac) self._generic_kdc_exchange(kdc_exchange_dict, cname=None, @@ -577,6 +580,18 @@ class S4UKerberosTests(KDCBaseTest): 'allow_delegation': True }) + def test_constrained_delegation_no_auth_data_required(self): + # Test constrained delegation. + self._run_delegation_test( + { + 'expected_error_mode': 0, + 'allow_delegation': True, + 'service2_opts': { + 'no_auth_data_required': True + }, + 'expect_pac': False + }) + def test_constrained_delegation_existing_delegation_info(self): # Test constrained delegation with an existing S4U_DELEGATION_INFO # structure in the PAC. @@ -624,6 +639,35 @@ class S4UKerberosTests(KDCBaseTest): 'modify_service_tgt_fn': self.remove_ticket_pac }) + def test_constrained_delegation_no_client_pac_no_auth_data_required(self): + # Test constrained delegation when the client service ticket does not + # contain a PAC. + self._run_delegation_test( + { + 'expected_error_mode': (KDC_ERR_BADOPTION, + KDC_ERR_MODIFIED), + 'allow_delegation': True, + 'modify_client_tkt_fn': self.remove_ticket_pac, + 'expect_edata': False, + 'service2_opts': { + 'no_auth_data_required': True + } + }) + + def test_constrained_delegation_no_service_pac_no_auth_data_required(self): + # Test constrained delegation when the service TGT does not contain a + # PAC. + self._run_delegation_test( + { + 'expected_error_mode': (KDC_ERR_BADOPTION, + KDC_ERR_MODIFIED), + 'allow_delegation': True, + 'modify_service_tgt_fn': self.remove_ticket_pac, + 'service2_opts': { + 'no_auth_data_required': True + } + }) + def test_constrained_delegation_non_forwardable(self): # Test constrained delegation with a non-forwardable ticket. self._run_delegation_test( @@ -645,6 +689,18 @@ class S4UKerberosTests(KDCBaseTest): 'allow_delegation': True }) + def test_rbcd_no_auth_data_required(self): + self._run_delegation_test( + { + 'expected_error_mode': 0, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'service2_opts': { + 'no_auth_data_required': True + }, + 'expect_pac': False + }) + def test_rbcd_existing_delegation_info(self): # Test constrained delegation with an existing S4U_DELEGATION_INFO # structure in the PAC. @@ -712,6 +768,55 @@ class S4UKerberosTests(KDCBaseTest): 'modify_service_tgt_fn': self.remove_ticket_pac }) + def test_rbcd_no_client_pac_no_auth_data_required_a(self): + # Test constrained delegation when the client service ticket does not + # contain a PAC, and an empty msDS-AllowedToDelegateTo attribute. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_MODIFIED, + 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': self.remove_ticket_pac, + 'service2_opts': { + 'no_auth_data_required': True + } + }) + + def test_rbcd_no_client_pac_no_auth_data_required_b(self): + # Test constrained delegation when the client service ticket does not + # contain a PAC, and a non-empty msDS-AllowedToDelegateTo attribute. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_MODIFIED, + 'expected_status': ntstatus.NT_STATUS_NO_MATCH, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_client_tkt_fn': self.remove_ticket_pac, + 'service1_opts': { + 'delegation_to_spn': ('host/test') + }, + 'service2_opts': { + 'no_auth_data_required': True + } + }) + + def test_rbcd_no_service_pac_no_auth_data_required(self): + # Test constrained delegation when the service TGT does not contain a + # PAC. + self._run_delegation_test( + { + 'expected_error_mode': KDC_ERR_BADOPTION, + 'expected_status': + ntstatus.NT_STATUS_NOT_FOUND, + 'allow_rbcd': True, + 'pac_options': '0001', # supports RBCD + 'modify_service_tgt_fn': self.remove_ticket_pac, + 'service2_opts': { + 'no_auth_data_required': True + } + }) + def test_rbcd_non_forwardable(self): # Test resource-based constrained delegation with a non-forwardable # ticket. diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index 683dbacb979..b1d7a1ebe8f 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -125,7 +125,7 @@ # S4U tests # ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum -^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac\(.*\)$ ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_existing_delegation_info ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_missing_client_checksum ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_a @@ -141,3 +141,9 @@ # KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case # ^samba4.krb5.kdc with machine account.as-req-pac-request.fl2000dc:local +# +# +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_auth_data_required +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_auth_data_required +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_no_auth_data_required_a +^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_no_auth_data_required_b -- 2.25.1 From 7e66447d134ed8778a67fb80ecdf95eced18e411 Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni Date: Wed, 10 Aug 2016 23:31:14 +0000 Subject: [PATCH 145/162] HEIMDAL:kdc: Fix transit path validation CVE-2017-6594 Commit f469fc6 (2010-10-02) inadvertently caused the previous hop realm to not be added to the transit path of issued tickets. This may, in some cases, enable bypass of capath policy in Heimdal versions 1.5 through 7.2. Note, this may break sites that rely on the bug. With the bug some incomplete [capaths] worked, that should not have. These may now break authentication in some cross-realm configurations. (similar to heimdal commit b1e699103f08d6a0ca46a122193c9da65f6cf837) BUG: https://bugzilla.samba.org/show_bug.cgi?id=12998 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Oct 20 10:58:37 UTC 2021 on sn-devel-184 (cherry picked from commit 7e961f3f7a815960ae25377d5b7515184d439690) --- source4/heimdal/kdc/krb5tgs.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index 2de3b099199..7e9379db64a 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -409,8 +409,12 @@ fix_transited_encoding(krb5_context context, "Decoding transited encoding"); return ret; } + + /* + * If the realm of the presented tgt is neither the client nor the server + * realm, it is a transit realm and must be added to transited set. + */ if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) { - /* not us, so add the previous realm to transited set */ if (num_realms + 1 > UINT_MAX/sizeof(*realms)) { ret = ERANGE; goto free_realms; @@ -492,6 +496,7 @@ tgs_make_reply(krb5_context context, const char *server_name, hdb_entry_ex *client, krb5_principal client_principal, + const char *tgt_realm, hdb_entry_ex *krbtgt, krb5_pac mspac, uint16_t rodc_id, @@ -553,7 +558,7 @@ tgs_make_reply(krb5_context context, &tgt->transited, &et, krb5_principal_get_realm(context, client_principal), krb5_principal_get_realm(context, server->entry.principal), - krb5_principal_get_realm(context, krbtgt->entry.principal)); + tgt_realm); if(ret) goto out; @@ -1292,13 +1297,14 @@ tgs_build_reply(krb5_context context, HDB *clientdb, *s4u2self_impersonated_clientdb; krb5_realm ref_realm = NULL; EncTicketPart *tgt = &ticket->ticket; + const char *tgt_realm = /* Realm of TGT issuer */ + krb5_principal_get_realm(context, krbtgt->entry.principal); const EncryptionKey *ekey; krb5_keyblock sessionkey; krb5_kvno kvno; krb5_pac mspac = NULL; uint16_t rodc_id; krb5_boolean add_ticket_sig = FALSE; - hdb_entry_ex *krbtgt_out = NULL; METHOD_DATA enc_pa_data; @@ -2036,6 +2042,7 @@ server_lookup: spn, client, cp, + tgt_realm, krbtgt_out, mspac, rodc_id, -- 2.25.1 From bde4bd981c78b89ec556f6d680473c303bbafffa Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Wed, 8 Sep 2021 17:01:26 +1200 Subject: [PATCH 146/162] pytest/rodc_rwdc: try to avoid race. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14868 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Douglas Bagnall Reviewed-by: Stefan Metzmacher (cherry picked from commit a169e013e66bab15e594ce49b805edebfcd503cf) --- source4/dsdb/tests/python/rodc_rwdc.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source4/dsdb/tests/python/rodc_rwdc.py b/source4/dsdb/tests/python/rodc_rwdc.py index a09d16a0163..b9ea18e5b68 100644 --- a/source4/dsdb/tests/python/rodc_rwdc.py +++ b/source4/dsdb/tests/python/rodc_rwdc.py @@ -251,6 +251,10 @@ class RodcRwdcCachedTests(password_lockout_base.BasePasswordTestCase): res = ldb_system.search(userdn, attrs=['unicodePwd']) self.assertTrue('unicodePwd' in res[0]) + # force replication here to flush any pending preloads (this + # was a racy test). + self.force_replication() + newpass = userpass + '!' # Forcing replication should blank out password (when changed) -- 2.25.1 From 8f3d5dd7f3fd6cf9d7efedc4d8b0e2ad8a3571ca Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 20 Sep 2021 16:27:40 +1200 Subject: [PATCH 147/162] selftest: Increase account lockout windows to make test more realiable BUG: https://bugzilla.samba.org/show_bug.cgi?id=14868 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit 6292f0597f208d7953382341380921cf0fd0a8a8) --- source4/dsdb/tests/python/rodc_rwdc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/dsdb/tests/python/rodc_rwdc.py b/source4/dsdb/tests/python/rodc_rwdc.py index b9ea18e5b68..0340042e19d 100644 --- a/source4/dsdb/tests/python/rodc_rwdc.py +++ b/source4/dsdb/tests/python/rodc_rwdc.py @@ -289,14 +289,14 @@ class RodcRwdcCachedTests(password_lockout_base.BasePasswordTestCase): m = ldb.Message() m.dn = ldb.Dn(self.ldb, self.base_dn) - self.account_lockout_duration = 10 + self.account_lockout_duration = 15 account_lockout_duration_ticks = -int(self.account_lockout_duration * (1e7)) m["lockoutDuration"] = ldb.MessageElement(str(account_lockout_duration_ticks), ldb.FLAG_MOD_REPLACE, "lockoutDuration") - self.lockout_observation_window = 10 + self.lockout_observation_window = 15 lockout_observation_window_ticks = -int(self.lockout_observation_window * (1e7)) m["lockOutObservationWindow"] = ldb.MessageElement(str(lockout_observation_window_ticks), -- 2.25.1 From 7cd0018584ce76323cfab333d11a59fe07249b51 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Fri, 6 Aug 2021 11:08:10 +1200 Subject: [PATCH 148/162] pytest: dynamic tests optionally add __doc__ BUG: https://bugzilla.samba.org/show_bug.cgi?id=14869 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Douglas Bagnall Reviewed-by: Stefan Metzmacher (cherry picked from commit aacb18f920349e13b562c7c97901a0be7b273137) --- python/samba/tests/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py index 38f65f17e35..d895802c34f 100644 --- a/python/samba/tests/__init__.py +++ b/python/samba/tests/__init__.py @@ -71,7 +71,7 @@ class TestCase(unittest.TestCase): """A Samba test case.""" @classmethod - def generate_dynamic_test(cls, fnname, suffix, *args): + def generate_dynamic_test(cls, fnname, suffix, *args, doc=None): """ fnname is something like "test_dynamic_sum" suffix is something like "1plus2" @@ -84,6 +84,7 @@ class TestCase(unittest.TestCase): """ def fn(self): getattr(self, "_%s_with_args" % fnname)(*args) + fn.__doc__ = doc setattr(cls, "%s_%s" % (fnname, suffix), fn) @classmethod -- 2.25.1 From 7254c308d05eca527c46319522bd671a8ea912cf Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 8 Oct 2021 15:40:09 +1300 Subject: [PATCH 149/162] selftest: krb5 account creation: clarify account type as an enum This makes the code clearer with a symbolic constant rather than a True/False boolean. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14869 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit 49306f74eb29a2192019fab9260f9d242f9d5fd9) --- .../tests/krb5/as_canonicalization_tests.py | 7 ++- python/samba/tests/krb5/kdc_base_test.py | 63 ++++++++++++------- python/samba/tests/krb5/kdc_tgs_tests.py | 7 ++- .../ms_kile_client_principal_lookup_tests.py | 36 +++++++---- python/samba/tests/krb5/rodc_tests.py | 4 +- python/samba/tests/krb5/s4u_tests.py | 35 ++++++----- python/samba/tests/krb5/test_ccache.py | 11 ++-- 7 files changed, 100 insertions(+), 63 deletions(-) diff --git a/python/samba/tests/krb5/as_canonicalization_tests.py b/python/samba/tests/krb5/as_canonicalization_tests.py index 9538d0ae3cf..674fcb37101 100755 --- a/python/samba/tests/krb5/as_canonicalization_tests.py +++ b/python/samba/tests/krb5/as_canonicalization_tests.py @@ -171,9 +171,10 @@ class KerberosASCanonicalizationTests(KDCBaseTest): def machine_account_creds(self): if self.machine_creds is None: samdb = self.get_samdb() - self.machine_creds, _ = self.create_account(samdb, - MACHINE_NAME, - machine_account=True) + self.machine_creds, _ = self.create_account( + samdb, + MACHINE_NAME, + account_type=self.AccountType.COMPUTER) self.machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA) self.machine_creds.set_kerberos_state(DONT_USE_KERBEROS) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 1fc15315b0b..7cd3c5255f2 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -23,6 +23,7 @@ import tempfile import binascii import collections import secrets +from enum import Enum, auto from collections import namedtuple import ldb @@ -90,6 +91,10 @@ class KDCBaseTest(RawKerberosTest): """ Base class for KDC tests. """ + class AccountType(Enum): + USER = auto() + COMPUTER = auto() + @classmethod def setUpClass(cls): super().setUpClass() @@ -230,7 +235,7 @@ class KDCBaseTest(RawKerberosTest): return default_enctypes - def create_account(self, samdb, name, machine_account=False, + def create_account(self, samdb, name, account_type=AccountType.USER, spn=None, upn=None, additional_details=None, ou=None, account_control=0): '''Create an account for testing. @@ -238,8 +243,10 @@ class KDCBaseTest(RawKerberosTest): which is used by tearDownClass to clean up the created accounts. ''' if ou is None: - guid = (DS_GUID_COMPUTERS_CONTAINER if machine_account - else DS_GUID_USERS_CONTAINER) + if account_type is account_type.COMPUTER: + guid = DS_GUID_COMPUTERS_CONTAINER + else: + guid = DS_GUID_USERS_CONTAINER ou = samdb.get_wellknown_dn(samdb.get_default_basedn(), guid) @@ -248,14 +255,17 @@ class KDCBaseTest(RawKerberosTest): # remove the account if it exists, this will happen if a previous test # run failed delete_force(samdb, dn) - if machine_account: - object_class = "computer" - account_name = "%s$" % name - account_control |= UF_WORKSTATION_TRUST_ACCOUNT - else: + if account_type is self.AccountType.USER: object_class = "user" account_name = name account_control |= UF_NORMAL_ACCOUNT + else: + object_class = "computer" + account_name = "%s$" % name + if account_type is self.AccountType.COMPUTER: + account_control |= UF_WORKSTATION_TRUST_ACCOUNT + else: + self.fail() password = generate_random_password(32, 32) utf16pw = ('"%s"' % password).encode('utf-16-le') @@ -267,6 +277,10 @@ class KDCBaseTest(RawKerberosTest): "userAccountControl": str(account_control), "unicodePwd": utf16pw} if spn is not None: + if isinstance(spn, str): + spn = spn.format(account=account_name) + else: + spn = tuple(s.format(account=account_name) for s in spn) details["servicePrincipalName"] = spn if upn is not None: details["userPrincipalName"] = upn @@ -280,10 +294,10 @@ class KDCBaseTest(RawKerberosTest): creds.set_domain(samdb.domain_netbios_name().upper()) creds.set_password(password) creds.set_username(account_name) - if machine_account: - creds.set_workstation(name) - else: + if account_type is self.AccountType.USER: creds.set_workstation('') + else: + creds.set_workstation(name) creds.set_dn(ldb.Dn(samdb, dn)) creds.set_spn(spn) # @@ -609,13 +623,14 @@ class KDCBaseTest(RawKerberosTest): return cleanup def get_cached_creds(self, *, - machine_account, + account_type, opts=None, use_cache=True): if opts is None: opts = {} opts_default = { + 'spn': None, 'allowed_replication': False, 'allowed_replication_mock': False, 'denied_replication': False, @@ -632,7 +647,7 @@ class KDCBaseTest(RawKerberosTest): } account_opts = { - 'machine_account': machine_account, + 'account_type': account_type, **opts_default, **opts } @@ -651,7 +666,8 @@ class KDCBaseTest(RawKerberosTest): return creds def create_account_opts(self, *, - machine_account, + account_type, + spn, allowed_replication, allowed_replication_mock, denied_replication, @@ -665,12 +681,13 @@ class KDCBaseTest(RawKerberosTest): delegation_from_dn, trusted_to_auth_for_delegation, fast_support): - if machine_account: - self.assertFalse(not_delegated) - else: + if account_type is self.AccountType.USER: + self.assertIsNone(spn) self.assertIsNone(delegation_to_spn) self.assertIsNone(delegation_from_dn) self.assertFalse(trusted_to_auth_for_delegation) + else: + self.assertFalse(not_delegated) samdb = self.get_samdb() rodc_samdb = self.get_rodc_samdb() @@ -707,13 +724,11 @@ class KDCBaseTest(RawKerberosTest): details['msDS-AllowedToActOnBehalfOfOtherIdentity'] = ( security_descriptor) - if machine_account: + if spn is None and account_type is not self.AccountType.USER: spn = 'host/' + user_name - else: - spn = None creds, dn = self.create_account(samdb, user_name, - machine_account=machine_account, + account_type=account_type, spn=spn, additional_details=details, account_control=user_account_control) @@ -787,7 +802,7 @@ class KDCBaseTest(RawKerberosTest): allow_missing_password=False, allow_missing_keys=True): def create_client_account(): - return self.get_cached_creds(machine_account=False) + return self.get_cached_creds(account_type=self.AccountType.USER) c = self._get_krb5_creds(prefix='CLIENT', allow_missing_password=allow_missing_password, @@ -799,7 +814,7 @@ class KDCBaseTest(RawKerberosTest): allow_missing_password=False, allow_missing_keys=True): def create_mach_account(): - return self.get_cached_creds(machine_account=True, + return self.get_cached_creds(account_type=self.AccountType.COMPUTER, opts={'fast_support': True}) c = self._get_krb5_creds(prefix='MAC', @@ -813,7 +828,7 @@ class KDCBaseTest(RawKerberosTest): allow_missing_keys=True): def create_service_account(): return self.get_cached_creds( - machine_account=True, + account_type=self.AccountType.COMPUTER, opts={ 'trusted_to_auth_for_delegation': True, 'fast_support': True diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py index 9d846a2c3ad..f36704f998c 100755 --- a/python/samba/tests/krb5/kdc_tgs_tests.py +++ b/python/samba/tests/krb5/kdc_tgs_tests.py @@ -148,7 +148,8 @@ class KdcTgsTests(KDCBaseTest): samdb = self.get_samdb() user_name = "tsttktusr" (uc, dn) = self.create_account(samdb, user_name) - (mc, _) = self.create_account(samdb, "tsttktmac", machine_account=True) + (mc, _) = self.create_account(samdb, "tsttktmac", + account_type=self.AccountType.COMPUTER) realm = uc.get_realm().lower() # Do the initial AS-REQ, should get a pre-authentication required @@ -282,7 +283,7 @@ class KdcTgsTests(KDCBaseTest): def test_client_no_auth_data_required(self): client_creds = self.get_cached_creds( - machine_account=False, + account_type=self.AccountType.USER, opts={'no_auth_data_required': True}) service_creds = self.get_service_creds() @@ -299,7 +300,7 @@ class KdcTgsTests(KDCBaseTest): def test_service_no_auth_data_required(self): client_creds = self.get_client_creds() service_creds = self.get_cached_creds( - machine_account=True, + account_type=self.AccountType.COMPUTER, opts={'no_auth_data_required': True}) tgt = self.get_tgt(client_creds) diff --git a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py index 2ee3d4a2a83..0aa3309b814 100755 --- a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py +++ b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py @@ -95,7 +95,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): realm = uc.get_realm().lower() mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response @@ -151,7 +152,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): # samdb = self.get_samdb() mach_name = "mskilemac" - (mc, dn) = self.create_account(samdb, mach_name, machine_account=True) + (mc, dn) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) realm = mc.get_realm().lower() # Do the initial AS-REQ, should get a pre-authentication required @@ -215,7 +217,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): realm = uc.get_realm().lower() mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response @@ -286,7 +289,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec) mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH # we should get a valid AS-RESP @@ -351,7 +355,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec) mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response @@ -420,7 +425,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec) mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response @@ -459,7 +465,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): realm = uc.get_realm().lower() mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response @@ -523,7 +530,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): ename = user_name + "@" + realm mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response @@ -586,7 +594,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): realm = uc.get_realm().lower() mach_name = "mskilemac" - (mc, dn) = self.create_account(samdb, mach_name, machine_account=True) + (mc, dn) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) ename = mach_name + "@" + realm uname = mach_name + "$@" + realm @@ -661,7 +670,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): ename = alt_name + "@" + realm mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH # we should get a valid AS-RESP @@ -728,7 +738,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): uname = user_name + "@" + realm mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response @@ -798,7 +809,8 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest): ename = alt_name + "@" + realm mach_name = "mskilemac" - (mc, _) = self.create_account(samdb, mach_name, machine_account=True) + (mc, _) = self.create_account(samdb, mach_name, + account_type=self.AccountType.COMPUTER) # Do the initial AS-REQ, should get a pre-authentication required # response diff --git a/python/samba/tests/krb5/rodc_tests.py b/python/samba/tests/krb5/rodc_tests.py index 4579f9eb552..302ae865cf1 100755 --- a/python/samba/tests/krb5/rodc_tests.py +++ b/python/samba/tests/krb5/rodc_tests.py @@ -39,12 +39,12 @@ class RodcKerberosTests(KDCBaseTest): # and including the RODCIdentifier. def test_rodc_ticket_signature(self): user_creds = self.get_cached_creds( - machine_account=False, + account_type=self.AccountType.USER, opts={ 'revealed_to_rodc': True }) target_creds = self.get_cached_creds( - machine_account=True, + account_type=self.AccountType.COMPUTER, opts={ 'revealed_to_rodc': True }) diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py index bbb7135b55b..ea629d29706 100755 --- a/python/samba/tests/krb5/s4u_tests.py +++ b/python/samba/tests/krb5/s4u_tests.py @@ -220,12 +220,14 @@ class S4UKerberosTests(KDCBaseTest): def _run_s4u2self_test(self, kdc_dict): client_opts = kdc_dict.pop('client_opts', None) - client_creds = self.get_cached_creds(machine_account=False, - opts=client_opts) + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER, + opts=client_opts) service_opts = kdc_dict.pop('service_opts', None) - service_creds = self.get_cached_creds(machine_account=True, - opts=service_opts) + service_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER, + opts=service_opts) service_tgt = self.get_tgt(service_creds) modify_service_tgt_fn = kdc_dict.pop('modify_service_tgt_fn', None) @@ -432,8 +434,9 @@ class S4UKerberosTests(KDCBaseTest): def _run_delegation_test(self, kdc_dict): client_opts = kdc_dict.pop('client_opts', None) - client_creds = self.get_cached_creds(machine_account=False, - opts=client_opts) + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER, + opts=client_opts) service1_opts = kdc_dict.pop('service1_opts', {}) service2_opts = kdc_dict.pop('service2_opts', {}) @@ -443,24 +446,28 @@ class S4UKerberosTests(KDCBaseTest): self.assertFalse(allow_delegation and allow_rbcd) if allow_rbcd: - service1_creds = self.get_cached_creds(machine_account=True, - opts=service1_opts) + service1_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER, + opts=service1_opts) self.assertNotIn('delegation_from_dn', service2_opts) service2_opts['delegation_from_dn'] = str(service1_creds.get_dn()) - service2_creds = self.get_cached_creds(machine_account=True, - opts=service2_opts) + service2_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER, + opts=service2_opts) else: - service2_creds = self.get_cached_creds(machine_account=True, - opts=service2_opts) + service2_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER, + opts=service2_opts) if allow_delegation: self.assertNotIn('delegation_to_spn', service1_opts) service1_opts['delegation_to_spn'] = service2_creds.get_spn() - service1_creds = self.get_cached_creds(machine_account=True, - opts=service1_opts) + service1_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER, + opts=service1_opts) client_tkt_options = kdc_dict.pop('client_tkt_options', 'forwardable') expected_flags = krb5_asn1.TicketFlags(client_tkt_options) diff --git a/python/samba/tests/krb5/test_ccache.py b/python/samba/tests/krb5/test_ccache.py index c44ea02d504..6a2b78398ac 100755 --- a/python/samba/tests/krb5/test_ccache.py +++ b/python/samba/tests/krb5/test_ccache.py @@ -55,11 +55,12 @@ class CcacheTests(KDCBaseTest): (user_credentials, _) = self.create_account(samdb, user_name) # Create the machine account. - (mach_credentials, _) = self.create_account(samdb, - mach_name, - machine_account=True, - spn="%s/%s" % (service, - mach_name)) + (mach_credentials, _) = self.create_account( + samdb, + mach_name, + account_type=self.AccountType.COMPUTER, + spn="%s/%s" % (service, + mach_name)) # Talk to the KDC to obtain the service ticket, which gets placed into # the cache. The machine account name has to match the name in the -- 2.25.1 From 74fe73c5a8535ce3e22ef2da42be1be3893568cc Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 18 Oct 2021 20:44:54 +1300 Subject: [PATCH 150/162] selftest: Remove duplicate setup of $base_dn and $ldbmodify These are already set up to the same values above for the full DC and correct values for the (strange) s4member environment. By not setting $base_dn again we avoid an error once we start checking for them. Signed-off-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 (cherry picked from commit 2c0658d408f17af2abc223b0cb18d8d33e0ecd1a) --- selftest/target/Samba4.pm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 99990fea2df..8bd489ea6a5 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1108,10 +1108,6 @@ servicePrincipalName: http/testupnspn.$ctx->{dnsname} } # Change the userPrincipalName for jane - $ldbmodify = ${cmd_env}; - $ldbmodify .= Samba::bindir_path($self, "ldbmodify"); - $ldbmodify .= " --configfile=$ctx->{smb_conf}"; - $base_dn = "DC=".join(",DC=", split(/\./, $ctx->{realm})); $user_dn = "cn=jane,cn=users,$base_dn"; open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb"); -- 2.25.1 From 1b10de86ae8123cc939452faedd192b76256aab0 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 18 Oct 2021 11:55:14 +1300 Subject: [PATCH 151/162] selftest: Improve error handling and perl style when setting up users in Samba4.pm This catches errors and avoids using global varibles (the old style file handles are global). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14869 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher (cherry picked from commit 459200caba04fd83ed650b9cdfe5b158cf9a149f) --- selftest/target/Samba4.pm | 72 ++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 8bd489ea6a5..7c17060dcb0 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -239,12 +239,19 @@ sub wait_for_start($$) sub write_ldb_file($$$) { - my ($self, $file, $ldif) = @_; + my ($self, $file, $ldif_in) = @_; my $ldbadd = Samba::bindir_path($self, "ldbadd"); - open(LDIF, "|$ldbadd -H $file >/dev/null"); - print LDIF $ldif; - return(close(LDIF)); + open(my $ldif, "|$ldbadd -H $file > /dev/null") + or die "Failed to run $ldbadd: $!"; + print $ldif $ldif_in; + close($ldif); + + unless ($? == 0) { + warn("$ldbadd failed: $?"); + return undef; + } + return 1; } sub add_wins_config($$) @@ -946,6 +953,8 @@ sub provision_raw_step2($$$) { my ($self, $ctx, $ret) = @_; + my $ldif; + my $provision_cmd = join(" ", @{$ctx->{provision_options}}); unless (system($provision_cmd) == 0) { warn("Unable to provision: \n$provision_cmd\n"); @@ -991,17 +1000,23 @@ sub provision_raw_step2($$$) my $user_dn = "cn=$testallowed_account,cn=users,$base_dn"; $testallowed_account = "testallowed account"; - open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb"); - print LDIF "dn: $user_dn + open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb") + or die "Failed to run $ldbmodify: $!"; + print $ldif "dn: $user_dn changetype: modify replace: samAccountName samAccountName: $testallowed_account - "; - close(LDIF); + close($ldif); + unless ($? == 0) { + warn("$ldbmodify failed: $?"); + return undef; + } - open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb"); - print LDIF "dn: $user_dn + open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb") + or die "Failed to run $ldbmodify: $!"; + print $ldif "dn: $user_dn changetype: modify replace: userPrincipalName userPrincipalName: testallowed upn\@$ctx->{realm} @@ -1009,7 +1024,11 @@ replace: servicePrincipalName servicePrincipalName: host/testallowed - "; - close(LDIF); + close($ldif); + unless ($? == 0) { + warn("$ldbmodify failed: $?"); + return undef; + } $samba_tool_cmd = ${cmd_env}; $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool") @@ -1020,14 +1039,19 @@ servicePrincipalName: host/testallowed } $user_dn = "cn=testdenied,cn=users,$base_dn"; - open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb"); - print LDIF "dn: $user_dn + open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb") + or die "Failed to run $ldbmodify: $!"; + print $ldif "dn: $user_dn changetype: modify replace: userPrincipalName userPrincipalName: testdenied_upn\@$ctx->{realm}.upn - "; - close(LDIF); + close($ldif); + unless ($? == 0) { + warn("$ldbmodify failed: $?"); + return undef; + } $samba_tool_cmd = ${cmd_env}; $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool") @@ -1038,8 +1062,9 @@ userPrincipalName: testdenied_upn\@$ctx->{realm}.upn } $user_dn = "cn=testupnspn,cn=users,$base_dn"; - open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb"); - print LDIF "dn: $user_dn + open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb") + or die "Failed to run $ldbmodify: $!"; + print $ldif "dn: $user_dn changetype: modify replace: userPrincipalName userPrincipalName: http/testupnspn.$ctx->{dnsname}\@$ctx->{realm} @@ -1047,7 +1072,11 @@ replace: servicePrincipalName servicePrincipalName: http/testupnspn.$ctx->{dnsname} - "; - close(LDIF); + close($ldif); + unless ($? == 0) { + warn("$ldbmodify failed: $?"); + return undef; + } $samba_tool_cmd = ${cmd_env}; $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool") @@ -1110,14 +1139,19 @@ servicePrincipalName: http/testupnspn.$ctx->{dnsname} # Change the userPrincipalName for jane $user_dn = "cn=jane,cn=users,$base_dn"; - open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb"); - print LDIF "dn: $user_dn + open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb") + or die "Failed to run $ldbmodify: $!"; + print $ldif "dn: $user_dn changetype: modify replace: userPrincipalName userPrincipalName: jane.doe\@$ctx->{realm} - "; - close(LDIF); + close($ldif); + unless ($? == 0) { + warn("$ldbmodify failed: $?"); + return undef; + } return $ret; } -- 2.25.1 From 56a86c4bc2567282d80e8fbf0bc527ca3b73ad02 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 4 Oct 2021 13:02:35 +0200 Subject: [PATCH 152/162] waf: Allow building with MIT KRB5 >= 1.20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gssrpc/xdr.h:105:1: error: function declaration isn’t a prototype [-Werror=strict-prototypes] 105 | typedef bool_t (*xdrproc_t)(); | ^~~~~~~ This can't be fixed, as the protoype is variadic. It can take up to three arguments. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14870 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher (cherry picked from commit 5d8e794551b5df835f07e2bd8348fef746144601) --- source4/kdc/wscript_build | 1 + 1 file changed, 1 insertion(+) diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build index c1f9a478582..0edca94e75f 100644 --- a/source4/kdc/wscript_build +++ b/source4/kdc/wscript_build @@ -29,6 +29,7 @@ if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'): if bld.CONFIG_GET('SAMBA_USES_MITKDC'): bld.SAMBA_MODULE('service_kdc', source='kdc-service-mit.c', + cflags_end='-Wno-strict-prototypes', subsystem='service', init_function='server_service_mitkdc_init', deps=''' -- 2.25.1 From 66d7d1808a17e2caede36f5b5b57b7071a64fdde Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Oct 2021 18:04:55 +0200 Subject: [PATCH 153/162] selftest/Samba3: remove unused close(USERMAP); calls BUG: https://bugzilla.samba.org/show_bug.cgi?id=14869 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett [abartlet@samba.org backported from commit d998f7f8df215866ab32e05be772e24fc0b2131c as offline login tests are not in Samba 4.14] --- selftest/target/Samba3.pm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index c15057fa80b..8679a48dd54 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -733,7 +733,6 @@ sub provision_ad_member mkdir($_, 0777) foreach(@dirs); - close(USERMAP); $ret->{DOMAIN} = $dcvars->{DOMAIN}; $ret->{REALM} = $dcvars->{REALM}; $ret->{DOMSID} = $dcvars->{DOMSID}; @@ -882,7 +881,6 @@ sub setup_ad_member_rfc2307 $ret or return undef; - close(USERMAP); $ret->{DOMAIN} = $dcvars->{DOMAIN}; $ret->{REALM} = $dcvars->{REALM}; $ret->{DOMSID} = $dcvars->{DOMSID}; @@ -980,7 +978,6 @@ sub setup_ad_member_idmap_rid $ret or return undef; - close(USERMAP); $ret->{DOMAIN} = $dcvars->{DOMAIN}; $ret->{REALM} = $dcvars->{REALM}; $ret->{DOMSID} = $dcvars->{DOMSID}; @@ -1078,7 +1075,6 @@ sub setup_ad_member_idmap_ad $ret or return undef; - close(USERMAP); $ret->{DOMAIN} = $dcvars->{DOMAIN}; $ret->{REALM} = $dcvars->{REALM}; $ret->{DOMSID} = $dcvars->{DOMSID}; -- 2.25.1 From ba314857e07dfac08adb15920f8d9debc63b40e2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 5 Oct 2021 16:42:00 +0200 Subject: [PATCH 154/162] selftest/Samba3: replace (winbindd => "yes", skip_wait => 1) with (winbindd => "offline") This is much more flexible and concentrates the logic in a single place. We'll use winbindd => "offline" in other places soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14870 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 4dc3c68c9a28f71888e3d6dd3b1f0bcdb8fa45de) --- selftest/target/Samba3.pm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 8679a48dd54..8de5fe6a374 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -789,7 +789,7 @@ sub provision_ad_member nmbd => "yes", winbindd => "yes", smbd => "yes")) { - return undef; + return undef; } $ret->{DC_SERVER} = $dcvars->{SERVER}; @@ -1874,7 +1874,7 @@ sub check_or_start($$) { LOG_FILE => $env_vars->{WINBINDD_TEST_LOG}, PCAP_FILE => "env-$ENV{ENVNAME}-winbindd", }; - if ($winbindd ne "yes") { + if ($winbindd ne "yes" and $winbindd ne "offline") { $daemon_ctx->{SKIP_DAEMON} = 1; } @@ -3069,13 +3069,17 @@ sub wait_for_start($$$$$) } } - if ($winbindd eq "yes") { + if ($winbindd eq "yes" or $winbindd eq "offline") { print "checking for winbindd\n"; my $count = 0; $cmd = "SELFTEST_WINBINDD_SOCKET_DIR='$envvars->{SELFTEST_WINBINDD_SOCKET_DIR}' "; $cmd .= "NSS_WRAPPER_PASSWD='$envvars->{NSS_WRAPPER_PASSWD}' "; $cmd .= "NSS_WRAPPER_GROUP='$envvars->{NSS_WRAPPER_GROUP}' "; - $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping-dc"; + if ($winbindd eq "yes") { + $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping-dc"; + } elsif ($winbindd eq "offline") { + $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping"; + } do { $ret = system($cmd); -- 2.25.1 From 5123a9d724f44ebfeeab1124e7d3e51b0d92df42 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 20 Oct 2021 12:39:05 +1300 Subject: [PATCH 155/162] tests/krb5: Decrease length of test account prefix This allows us more room to test with different account names. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit a5a6296e57cab2b53617d997c37b4e92d4124cc7) --- python/samba/tests/krb5/kdc_base_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 7cd3c5255f2..8f453b464fd 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -108,7 +108,7 @@ class KDCBaseTest(RawKerberosTest): # An identifier to ensure created accounts have unique names. Windows # caches accounts based on usernames, so account names being different # across test runs avoids previous test runs affecting the results. - cls.account_base = f'krb5_{secrets.token_hex(5)}_' + cls.account_base = f'{secrets.token_hex(4)}_' cls.account_id = 0 # A set containing DNs of accounts created as part of testing. -- 2.25.1 From 8c3f47a4c95ab6cc6301088c19d35f9350addfe8 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 20 Oct 2021 12:41:39 +1300 Subject: [PATCH 156/162] tests/krb5: Allow specifying prefix or suffix for test account names BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit 7e39994ed341883ac4c8c257220c19dbf70c7bc5) --- python/samba/tests/krb5/kdc_base_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 8f453b464fd..d8f3969d228 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -630,6 +630,8 @@ class KDCBaseTest(RawKerberosTest): opts = {} opts_default = { + 'name_prefix': None, + 'name_suffix': None, 'spn': None, 'allowed_replication': False, 'allowed_replication_mock': False, @@ -667,6 +669,8 @@ class KDCBaseTest(RawKerberosTest): def create_account_opts(self, *, account_type, + name_prefix, + name_suffix, spn, allowed_replication, allowed_replication_mock, @@ -696,6 +700,10 @@ class KDCBaseTest(RawKerberosTest): user_name = self.account_base + str(self.account_id) type(self).account_id += 1 + if name_prefix is not None: + user_name = name_prefix + user_name + if name_suffix is not None: + user_name += name_suffix user_account_control = 0 if trusted_to_auth_for_delegation: -- 2.25.1 From ecdca0b83792e263dd26179bff7dbf25c1733e1f Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 20 Oct 2021 12:44:19 +1300 Subject: [PATCH 157/162] tests/krb5: Allow creating machine accounts without a trailing dollar BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit f4785ccfefe7c89f84ad847ca3c12f604172b321) --- python/samba/tests/krb5/kdc_base_test.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index d8f3969d228..35f168a3c83 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -237,7 +237,7 @@ class KDCBaseTest(RawKerberosTest): def create_account(self, samdb, name, account_type=AccountType.USER, spn=None, upn=None, additional_details=None, - ou=None, account_control=0): + ou=None, account_control=0, add_dollar=True): '''Create an account for testing. The dn of the created account is added to self.accounts, which is used by tearDownClass to clean up the created accounts. @@ -255,13 +255,14 @@ class KDCBaseTest(RawKerberosTest): # remove the account if it exists, this will happen if a previous test # run failed delete_force(samdb, dn) + account_name = name if account_type is self.AccountType.USER: object_class = "user" - account_name = name account_control |= UF_NORMAL_ACCOUNT else: object_class = "computer" - account_name = "%s$" % name + if add_dollar: + account_name += '$' if account_type is self.AccountType.COMPUTER: account_control |= UF_WORKSTATION_TRUST_ACCOUNT else: @@ -632,6 +633,7 @@ class KDCBaseTest(RawKerberosTest): opts_default = { 'name_prefix': None, 'name_suffix': None, + 'add_dollar': True, 'spn': None, 'allowed_replication': False, 'allowed_replication_mock': False, @@ -671,6 +673,7 @@ class KDCBaseTest(RawKerberosTest): account_type, name_prefix, name_suffix, + add_dollar, spn, allowed_replication, allowed_replication_mock, @@ -739,7 +742,8 @@ class KDCBaseTest(RawKerberosTest): account_type=account_type, spn=spn, additional_details=details, - account_control=user_account_control) + account_control=user_account_control, + add_dollar=add_dollar) keys = self.get_keys(samdb, dn) self.creds_set_keys(creds, keys) -- 2.25.1 From d5bea3beb6bbac7c3dcbb5d40a5d70cf096a4672 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 20 Oct 2021 12:45:08 +1300 Subject: [PATCH 158/162] tests/krb5: Allow specifying the UPN for test accounts BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit 889476d1754f8ce2a41557ed3bf5242c1293584e) --- python/samba/tests/krb5/kdc_base_test.py | 4 ++++ python/samba/tests/krb5/raw_testcase.py | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index 35f168a3c83..b24c6376ab0 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -300,6 +300,7 @@ class KDCBaseTest(RawKerberosTest): else: creds.set_workstation(name) creds.set_dn(ldb.Dn(samdb, dn)) + creds.set_upn(upn) creds.set_spn(spn) # # Save the account name so it can be deleted in tearDownClass @@ -634,6 +635,7 @@ class KDCBaseTest(RawKerberosTest): 'name_prefix': None, 'name_suffix': None, 'add_dollar': True, + 'upn': None, 'spn': None, 'allowed_replication': False, 'allowed_replication_mock': False, @@ -674,6 +676,7 @@ class KDCBaseTest(RawKerberosTest): name_prefix, name_suffix, add_dollar, + upn, spn, allowed_replication, allowed_replication_mock, @@ -740,6 +743,7 @@ class KDCBaseTest(RawKerberosTest): creds, dn = self.create_account(samdb, user_name, account_type=account_type, + upn=upn, spn=spn, additional_details=details, account_control=user_account_control, diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 0b9fe8e7a04..619a8d006b2 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -366,6 +366,7 @@ class KerberosCredentials(Credentials): self.forced_salt = None self.dn = None + self.upn = None self.spn = None def set_as_supported_enctypes(self, value): @@ -475,6 +476,12 @@ class KerberosCredentials(Credentials): def get_spn(self): return self.spn + def set_upn(self, upn): + self.upn = upn + + def get_upn(self): + return self.upn + class KerberosTicketCreds: def __init__(self, ticket, session_key, -- 2.25.1 From ee450c6d09822dbe109ec82ae22b83e5fd11c76c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 20 Oct 2021 12:45:47 +1300 Subject: [PATCH 159/162] tests/krb5: Fix account salt calculation to match Windows BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher (cherry picked from commit 25bdf4c994e4fdb74abbacb1e22237f3f2cc37fe) --- python/samba/tests/krb5/raw_testcase.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py index 619a8d006b2..f352615db1f 100644 --- a/python/samba/tests/krb5/raw_testcase.py +++ b/python/samba/tests/krb5/raw_testcase.py @@ -454,13 +454,22 @@ class KerberosCredentials(Credentials): if self.forced_salt is not None: return self.forced_salt + upn = self.get_upn() + if upn is not None: + salt_name = upn.rsplit('@', 1)[0].replace('/', '') + else: + salt_name = self.get_username() + if self.get_workstation(): + salt_name = self.get_username().lower() + if salt_name[-1] == '$': + salt_name = salt_name[:-1] salt_string = '%shost%s.%s' % ( self.get_realm().upper(), - self.get_username().lower().rsplit('$', 1)[0], + salt_name, self.get_realm().lower()) else: - salt_string = self.get_realm().upper() + self.get_username() + salt_string = self.get_realm().upper() + salt_name return salt_string.encode('utf-8') -- 2.25.1 From 6f125af9c21866c43553d03c4d36a240e1372fa3 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 20 Oct 2021 12:46:36 +1300 Subject: [PATCH 160/162] tests/krb5: Add tests for account salt calculation BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher [abartlet@samba.org backported from commit 46039baa81377df10e5b134e4bb064ed246795e4 as the no_preauth side of the testsuite shows differences in enctypes in Samba 4.14. The change is only in salt calculation so this is not vital] --- python/samba/tests/krb5/as_req_tests.py | 10 + python/samba/tests/krb5/salt_tests.py | 327 ++++++++++++++++++++++++ python/samba/tests/usage.py | 1 + selftest/knownfail.d/kdc-salt | 12 + selftest/knownfail_heimdal_kdc | 108 ++++++++ source4/selftest/tests.py | 8 + 6 files changed, 466 insertions(+) create mode 100755 python/samba/tests/krb5/salt_tests.py create mode 100644 selftest/knownfail.d/kdc-salt diff --git a/python/samba/tests/krb5/as_req_tests.py b/python/samba/tests/krb5/as_req_tests.py index 7d7baaebf24..08081928363 100755 --- a/python/samba/tests/krb5/as_req_tests.py +++ b/python/samba/tests/krb5/as_req_tests.py @@ -113,6 +113,13 @@ class AsReqKerberosTests(KDCBaseTest): def test_as_req_enc_timestamp(self): client_creds = self.get_client_creds() + self._run_as_req_enc_timestamp(client_creds) + + def test_as_req_enc_timestamp_mac(self): + client_creds = self.get_mach_creds() + self._run_as_req_enc_timestamp(client_creds) + + def _run_as_req_enc_timestamp(self, client_creds): client_account = client_creds.get_username() client_as_etypes = self.get_default_enctypes() client_kvno = client_creds.get_kvno() @@ -197,6 +204,9 @@ class AsReqKerberosTests(KDCBaseTest): pac_request=True) self.assertIsNotNone(as_rep) + return etype_info2 + + if __name__ == "__main__": global_asn1_print = False global_hexdump = False diff --git a/python/samba/tests/krb5/salt_tests.py b/python/samba/tests/krb5/salt_tests.py new file mode 100755 index 00000000000..ecbf618e40e --- /dev/null +++ b/python/samba/tests/krb5/salt_tests.py @@ -0,0 +1,327 @@ +#!/usr/bin/env python3 +# Unix SMB/CIFS implementation. +# Copyright (C) Stefan Metzmacher 2020 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import sys +import os + +import ldb + +from samba.tests.krb5.as_req_tests import AsReqKerberosTests +import samba.tests.krb5.kcrypto as kcrypto + +sys.path.insert(0, "bin/python") +os.environ["PYTHONUNBUFFERED"] = "1" + +global_asn1_print = False +global_hexdump = False + + +class SaltTests(AsReqKerberosTests): + + def setUp(self): + super().setUp() + self.do_asn1_print = global_asn1_print + self.do_hexdump = global_hexdump + + def _get_creds(self, *, + account_type, + opts=None): + try: + return self.get_cached_creds( + account_type=account_type, + opts=opts) + except ldb.LdbError: + self.fail() + + def _run_salt_test(self, client_creds): + expected_salt = self.get_salt(client_creds) + self.assertIsNotNone(expected_salt) + + etype_info2 = self._run_as_req_enc_timestamp(client_creds) + + self.assertEqual(etype_info2[0]['etype'], kcrypto.Enctype.AES256) + self.assertEqual(etype_info2[0]['salt'], expected_salt) + + def test_salt_at_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'name_suffix': 'foo@bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'foo@bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_case_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'name_suffix': 'Foo@bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_case_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'Foo@bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_double_at_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'name_suffix': 'foo@@bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_double_at_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'foo@@bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_start_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'name_prefix': '@foo'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_start_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_prefix': '@foo'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_end_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'name_suffix': 'foo@'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_end_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'foo@'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_at_end_no_dollar_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'foo@', + 'add_dollar': False}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_no_dollar_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'add_dollar': False}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_dollar_mid_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'foo$bar', + 'add_dollar': False}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_dollar_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'name_suffix': 'foo$bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_dollar_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'foo$bar'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_dollar_end_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'name_suffix': 'foo$'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_dollar_end_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'name_suffix': 'foo$'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'foo0'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'foo1'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'host/foo2'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'host/foo3'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_realm_user(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'foo4@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_realm_mac(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'foo5@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_realm_user(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'host/foo6@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_realm_mac(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'host/foo7@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_dollar_realm_user(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'foo8$@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_dollar_realm_mac(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'foo9$@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_dollar_realm_user(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'host/foo10$@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_dollar_realm_mac(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'host/foo11$@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_other_realm_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'foo12@other.realm'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_other_realm_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'foo13@other.realm'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_other_realm_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'host/foo14@other.realm'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_other_realm_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'host/foo15@other.realm'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_case_user(self): + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'Foo16'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_case_mac(self): + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'Foo17'}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_dollar_mid_realm_user(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'foo$18@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_dollar_mid_realm_mac(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'foo$19@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_dollar_mid_realm_user(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'host/foo$20@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_host_dollar_mid_realm_mac(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'host/foo$21@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_at_realm_user(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.USER, + opts={'upn': 'foo22@bar@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + def test_salt_upn_at_realm_mac(self): + realm = self.get_samdb().domain_dns_name() + client_creds = self._get_creds( + account_type=self.AccountType.COMPUTER, + opts={'upn': 'foo23@bar@' + realm}) + self._run_as_req_enc_timestamp(client_creds) + + +if __name__ == "__main__": + global_asn1_print = False + global_hexdump = False + import unittest + unittest.main() diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py index e1711b532d7..4b68a2b798c 100644 --- a/python/samba/tests/usage.py +++ b/python/samba/tests/usage.py @@ -103,6 +103,7 @@ EXCLUDE_USAGE = { 'python/samba/tests/krb5/as_req_tests.py', 'python/samba/tests/krb5/fast_tests.py', 'python/samba/tests/krb5/rodc_tests.py', + 'python/samba/tests/krb5/salt_tests.py', } EXCLUDE_HELP = { diff --git a/selftest/knownfail.d/kdc-salt b/selftest/knownfail.d/kdc-salt new file mode 100644 index 00000000000..1a4ecd44624 --- /dev/null +++ b/selftest/knownfail.d/kdc-salt @@ -0,0 +1,12 @@ +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_case_mac +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_case_user +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_end_mac +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_end_no_dollar_mac +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_end_user +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_mac +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_start_mac +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_start_user +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_user +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_double_at_mac +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_double_at_user +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_upn_at_realm_user diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc index b1d7a1ebe8f..b39b11c3c53 100644 --- a/selftest/knownfail_heimdal_kdc +++ b/selftest/knownfail_heimdal_kdc @@ -71,6 +71,114 @@ ^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_False.fl2008r2dc ^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_None.fl2008r2dc ^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_True.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_False.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_None.fl2008r2dc +^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_True.fl2008r2dc # # FAST tests # diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 7aba1c6ce55..0703e5ceddf 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -1395,6 +1395,14 @@ for env in ["fl2008r2dc", "fl2003dc"]: 'TKT_SIG_SUPPORT': tkt_sig_support }) +planoldpythontestsuite('fl2008r2dc', 'samba.tests.krb5.salt_tests', + environ={ + 'ADMIN_USERNAME': '$USERNAME', + 'ADMIN_PASSWORD': '$PASSWORD', + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support + }) for env in ["rodc", "promoted_dc", "fl2000dc", "fl2008r2dc"]: if env == "rodc": -- 2.25.1 From ee07da2c75e5e467b3a480a6090c87e0e177c3ea Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 19 Oct 2021 16:01:36 +1300 Subject: [PATCH 161/162] dsdb: Allow special chars like "@" in samAccountName when generating the salt BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Oct 20 12:54:54 UTC 2021 on sn-devel-184 (cherry picked from commit 5eeb441b771a1ffe1ba1c69b72e8795f525a58ed) --- auth/credentials/credentials_krb5.c | 12 +- lib/krb5_wrap/krb5_samba.c | 192 +++++++++++++++--- lib/krb5_wrap/krb5_samba.h | 13 +- selftest/knownfail.d/kdc-salt | 11 - source3/passdb/machine_account_secrets.c | 10 +- .../dsdb/samdb/ldb_modules/password_hash.c | 23 ++- 6 files changed, 195 insertions(+), 66 deletions(-) diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c index 20e677e521a..61e55f7032d 100644 --- a/auth/credentials/credentials_krb5.c +++ b/auth/credentials/credentials_krb5.c @@ -1199,12 +1199,12 @@ _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, break; } - ret = smb_krb5_salt_principal(realm, - username, /* sAMAccountName */ - upn, /* userPrincipalName */ - uac_flags, - mem_ctx, - &salt_principal); + ret = smb_krb5_salt_principal_str(realm, + username, /* sAMAccountName */ + upn, /* userPrincipalName */ + uac_flags, + mem_ctx, + &salt_principal); if (ret) { talloc_free(mem_ctx); return ret; diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index 20ce86c708d..63a6e951f80 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -456,19 +456,20 @@ int smb_krb5_get_pw_salt(krb5_context context, * * @see smb_krb5_salt_principal2data */ -int smb_krb5_salt_principal(const char *realm, +int smb_krb5_salt_principal(krb5_context krb5_ctx, + const char *realm, const char *sAMAccountName, const char *userPrincipalName, uint32_t uac_flags, - TALLOC_CTX *mem_ctx, - char **_salt_principal) + krb5_principal *salt_princ) { TALLOC_CTX *frame = talloc_stackframe(); char *upper_realm = NULL; const char *principal = NULL; int principal_len = 0; + krb5_error_code krb5_ret; - *_salt_principal = NULL; + *salt_princ = NULL; if (sAMAccountName == NULL) { TALLOC_FREE(frame); @@ -512,7 +513,6 @@ int smb_krb5_salt_principal(const char *realm, */ if (uac_flags & UF_TRUST_ACCOUNT_MASK) { int computer_len = 0; - char *tmp = NULL; computer_len = strlen(sAMAccountName); if (sAMAccountName[computer_len-1] == '$') { @@ -520,60 +520,186 @@ int smb_krb5_salt_principal(const char *realm, } if (uac_flags & UF_INTERDOMAIN_TRUST_ACCOUNT) { - principal = talloc_asprintf(frame, "krbtgt/%*.*s", - computer_len, computer_len, - sAMAccountName); - if (principal == NULL) { + const char *krbtgt = "krbtgt"; + krb5_ret = krb5_build_principal_ext(krb5_ctx, + salt_princ, + strlen(upper_realm), + upper_realm, + strlen(krbtgt), + krbtgt, + computer_len, + sAMAccountName, + 0); + if (krb5_ret != 0) { TALLOC_FREE(frame); - return ENOMEM; + return krb5_ret; } } else { - - tmp = talloc_asprintf(frame, "host/%*.*s.%s", - computer_len, computer_len, - sAMAccountName, realm); + const char *host = "host"; + char *tmp = NULL; + char *tmp_lower = NULL; + + tmp = talloc_asprintf(frame, "%*.*s.%s", + computer_len, + computer_len, + sAMAccountName, + realm); if (tmp == NULL) { TALLOC_FREE(frame); return ENOMEM; } - principal = strlower_talloc(frame, tmp); - TALLOC_FREE(tmp); - if (principal == NULL) { + tmp_lower = strlower_talloc(frame, tmp); + if (tmp_lower == NULL) { TALLOC_FREE(frame); return ENOMEM; } - } - principal_len = strlen(principal); + krb5_ret = krb5_build_principal_ext(krb5_ctx, + salt_princ, + strlen(upper_realm), + upper_realm, + strlen(host), + host, + strlen(tmp_lower), + tmp_lower, + 0); + if (krb5_ret != 0) { + TALLOC_FREE(frame); + return krb5_ret; + } + } } else if (userPrincipalName != NULL) { - char *p; + /* + * We parse the name not only to allow an easy + * replacement of the realm (no matter the realm in + * the UPN, the salt comes from the upper-case real + * realm, but also to correctly provide a salt when + * the UPN is host/foo.bar + * + * This can fail for a UPN of the form foo@bar@REALM + * (which is accepted by windows) however. + */ + krb5_ret = krb5_parse_name(krb5_ctx, + userPrincipalName, + salt_princ); - principal = userPrincipalName; - p = strchr(principal, '@'); - if (p != NULL) { - principal_len = PTR_DIFF(p, principal); - } else { - principal_len = strlen(principal); + if (krb5_ret != 0) { + TALLOC_FREE(frame); + return krb5_ret; + } + + /* + * No matter what realm (including none) in the UPN, + * the realm is replaced with our upper-case realm + */ + smb_krb5_principal_set_realm(krb5_ctx, + *salt_princ, + upper_realm); + if (krb5_ret != 0) { + krb5_free_principal(krb5_ctx, *salt_princ); + TALLOC_FREE(frame); + return krb5_ret; } } else { principal = sAMAccountName; principal_len = strlen(principal); - } - *_salt_principal = talloc_asprintf(mem_ctx, "%*.*s@%s", - principal_len, principal_len, - principal, upper_realm); - if (*_salt_principal == NULL) { - TALLOC_FREE(frame); - return ENOMEM; + krb5_ret = krb5_build_principal_ext(krb5_ctx, + salt_princ, + strlen(upper_realm), + upper_realm, + principal_len, + principal, + 0); + if (krb5_ret != 0) { + TALLOC_FREE(frame); + return krb5_ret; + } } TALLOC_FREE(frame); return 0; } +/** + * @brief This constructs the salt principal used by active directory + * + * Most Kerberos encryption types require a salt in order to + * calculate the long term private key for user/computer object + * based on a password. + * + * The returned _salt_principal is a string in forms like this: + * - host/somehost.example.com@EXAMPLE.COM + * - SomeAccount@EXAMPLE.COM + * - SomePrincipal@EXAMPLE.COM + * + * This is not the form that's used as salt, it's just + * the human readable form. It needs to be converted by + * smb_krb5_salt_principal2data(). + * + * @param[in] realm The realm the user/computer is added too. + * + * @param[in] sAMAccountName The sAMAccountName attribute of the object. + * + * @param[in] userPrincipalName The userPrincipalName attribute of the object + * or NULL is not available. + * + * @param[in] uac_flags UF_ACCOUNT_TYPE_MASKed userAccountControl field + * + * @param[in] mem_ctx The TALLOC_CTX to allocate _salt_principal. + * + * @param[out] _salt_principal The resulting principal as string. + * + * @retval 0 Success; otherwise - Kerberos error codes + * + * @see smb_krb5_salt_principal2data + */ +int smb_krb5_salt_principal_str(const char *realm, + const char *sAMAccountName, + const char *userPrincipalName, + uint32_t uac_flags, + TALLOC_CTX *mem_ctx, + char **_salt_principal_str) +{ + krb5_principal salt_principal = NULL; + char *salt_principal_malloc; + krb5_context krb5_ctx; + krb5_error_code krb5_ret + = smb_krb5_init_context_common(&krb5_ctx); + if (krb5_ret != 0) { + DBG_ERR("kerberos init context failed (%s)\n", + error_message(krb5_ret)); + return krb5_ret; + } + + krb5_ret = smb_krb5_salt_principal(krb5_ctx, + realm, + sAMAccountName, + userPrincipalName, + uac_flags, + &salt_principal); + + krb5_ret = krb5_unparse_name(krb5_ctx, salt_principal, + &salt_principal_malloc); + if (krb5_ret != 0) { + krb5_free_principal(krb5_ctx, salt_principal); + DBG_ERR("kerberos unparse of salt principal failed (%s)\n", + error_message(krb5_ret)); + return krb5_ret; + } + krb5_free_principal(krb5_ctx, salt_principal); + *_salt_principal_str + = talloc_strdup(mem_ctx, salt_principal_malloc); + krb5_free_unparsed_name(krb5_ctx, salt_principal_malloc); + + if (*_salt_principal_str == NULL) { + return ENOMEM; + } + return 0; +} + /** * @brief Converts the salt principal string into the salt data blob * diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h index ca9a893e4f7..56a2a975278 100644 --- a/lib/krb5_wrap/krb5_samba.h +++ b/lib/krb5_wrap/krb5_samba.h @@ -350,12 +350,19 @@ krb5_error_code ms_suptypes_to_ietf_enctypes(TALLOC_CTX *mem_ctx, int smb_krb5_get_pw_salt(krb5_context context, krb5_const_principal host_princ, krb5_data *psalt); -int smb_krb5_salt_principal(const char *realm, +int smb_krb5_salt_principal(krb5_context krb5_ctx, + const char *realm, const char *sAMAccountName, const char *userPrincipalName, uint32_t uac_flags, - TALLOC_CTX *mem_ctx, - char **_salt_principal); + krb5_principal *salt_princ); + +int smb_krb5_salt_principal_str(const char *realm, + const char *sAMAccountName, + const char *userPrincipalName, + uint32_t uac_flags, + TALLOC_CTX *mem_ctx, + char **_salt_principal); int smb_krb5_salt_principal2data(krb5_context context, const char *salt_principal, TALLOC_CTX *mem_ctx, diff --git a/selftest/knownfail.d/kdc-salt b/selftest/knownfail.d/kdc-salt index 1a4ecd44624..a671e4d93eb 100644 --- a/selftest/knownfail.d/kdc-salt +++ b/selftest/knownfail.d/kdc-salt @@ -1,12 +1 @@ -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_case_mac -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_case_user -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_end_mac -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_end_no_dollar_mac -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_end_user -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_mac -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_start_mac -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_start_user -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_at_user -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_double_at_mac -^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_double_at_user ^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_upn_at_realm_user diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c index 5cda8f065c4..7c103d0a6e4 100644 --- a/source3/passdb/machine_account_secrets.c +++ b/source3/passdb/machine_account_secrets.c @@ -1573,11 +1573,11 @@ NTSTATUS secrets_store_JoinCtx(const struct libnet_JoinCtx *r) if (info->salt_principal == NULL && r->out.domain_is_ad) { char *p = NULL; - ret = smb_krb5_salt_principal(info->domain_info.dns_domain.string, - info->account_name, - NULL /* userPrincipalName */, - UF_WORKSTATION_TRUST_ACCOUNT, - info, &p); + ret = smb_krb5_salt_principal_str(info->domain_info.dns_domain.string, + info->account_name, + NULL /* userPrincipalName */, + UF_WORKSTATION_TRUST_ACCOUNT, + info, &p); if (ret != 0) { status = krb5_to_nt_status(ret); DBG_ERR("smb_krb5_salt_principal() failed " diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index bfdfa51595a..82d9e8ebd2e 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -685,8 +685,8 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io) { struct ldb_context *ldb; krb5_error_code krb5_ret; - char *salt_principal = NULL; - char *salt_data = NULL; + krb5_principal salt_principal = NULL; + krb5_data salt_data; krb5_data salt; krb5_keyblock key; krb5_data cleartext_data; @@ -697,11 +697,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io) cleartext_data.length = io->n.cleartext_utf8->length; uac_flags = io->u.userAccountControl & UF_ACCOUNT_TYPE_MASK; - krb5_ret = smb_krb5_salt_principal(io->ac->status->domain_data.realm, + krb5_ret = smb_krb5_salt_principal(io->smb_krb5_context->krb5_context, + io->ac->status->domain_data.realm, io->u.sAMAccountName, io->u.user_principal_name, uac_flags, - io->ac, &salt_principal); if (krb5_ret) { ldb_asprintf_errstring(ldb, @@ -715,8 +715,10 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io) /* * create salt from salt_principal */ - krb5_ret = smb_krb5_salt_principal2data(io->smb_krb5_context->krb5_context, - salt_principal, io->ac, &salt_data); + krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context, + salt_principal, &salt_data); + + krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal); if (krb5_ret) { ldb_asprintf_errstring(ldb, "setup_kerberos_keys: " @@ -725,12 +727,17 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io) krb5_ret, io->ac)); return LDB_ERR_OPERATIONS_ERROR; } - io->g.salt = salt_data; /* now use the talloced copy of the salt */ - salt.data = discard_const(io->g.salt); + salt.data = talloc_strndup(io->ac, + (char *)salt_data.data, + salt_data.length); + io->g.salt = salt.data; salt.length = strlen(io->g.salt); + smb_krb5_free_data_contents(io->smb_krb5_context->krb5_context, + &salt_data); + /* * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of * the salt and the cleartext password -- 2.25.1 From 63558be187c5aad165785fd2937271e3bd065026 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 22 Oct 2021 10:50:36 +1300 Subject: [PATCH 162/162] lib/krb5_wrap: Fix missing error check in new salt code CID 1492905: Control flow issues (DEADCODE) This was a regression in 5eeb441b771a1ffe1ba1c69b72e8795f525a58ed. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14874 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 Signed-off-by: Andrew Bartlett Reviewed-by: Andreas Schneider Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Sat Oct 23 08:07:13 UTC 2021 on sn-devel-184 (cherry picked from commit 5094d986b7686f057195dcb10764295b88967019) --- lib/krb5_wrap/krb5_samba.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index 63a6e951f80..fff5b4e2a22 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -594,9 +594,9 @@ int smb_krb5_salt_principal(krb5_context krb5_ctx, * No matter what realm (including none) in the UPN, * the realm is replaced with our upper-case realm */ - smb_krb5_principal_set_realm(krb5_ctx, - *salt_princ, - upper_realm); + krb5_ret = smb_krb5_principal_set_realm(krb5_ctx, + *salt_princ, + upper_realm); if (krb5_ret != 0) { krb5_free_principal(krb5_ctx, *salt_princ); TALLOC_FREE(frame); -- 2.25.1