From c8ef1ef980a1281ec7edd1788dad9e22889d995a Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Sat, 19 Sep 2020 14:16:20 +0200
Subject: [PATCH 19/99] s4:mit-kdb: Force canonicalization for looking up
 principals

See also
https://github.com/krb5/krb5/commit/ac8865a22138ab0c657208c41be8fd6bc7968148

Pair-Programmed-With: Andreas Schneider <asn@samba.org>
Signed-off-by: Isaac Boukris <iboukris@gmail.com>
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Alexander Bokovoy <ab@samba.org>

Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
Autobuild-Date(master): Mon Nov 29 09:32:26 UTC 2021 on sn-devel-184

(cherry picked from commit 90febd2a33b88af49af595fe0e995d6ba0f33a1b)
---
 selftest/knownfail_mit_kdc    | 14 --------------
 source4/heimdal/lib/hdb/hdb.h |  1 +
 source4/kdc/db-glue.c         |  7 ++++++-
 source4/kdc/mit_samba.c       |  8 ++++++++
 source4/kdc/sdb.h             |  1 +
 5 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index cc7b501c6bf..c046a46a4f3 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -379,8 +379,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_renew_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied
@@ -408,8 +406,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_user2user_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_sname
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_other_sname
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_req
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_krbtgt_link
@@ -422,10 +418,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_user2user_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_cname_host
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_correct_cname
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_correct_realm
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_other_cname
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_wrong_realm
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_srealm
@@ -471,12 +463,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_tgs_rodc_pac_request_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_pac_request_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_pac_request_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_user_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_user_pac_request_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_user_pac_request_true
 #
 # PAC requester SID tests
 #
diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h
index 5ef9d9565f3..dafaffc6c2d 100644
--- a/source4/heimdal/lib/hdb/hdb.h
+++ b/source4/heimdal/lib/hdb/hdb.h
@@ -63,6 +63,7 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK };
 #define HDB_F_ALL_KVNOS		2048	/* we want all the keys, live or not */
 #define HDB_F_FOR_AS_REQ	4096	/* fetch is for a AS REQ */
 #define HDB_F_FOR_TGS_REQ	8192	/* fetch is for a TGS REQ */
+#define HDB_F_FORCE_CANON	16384	/* force canonicalition */
 
 /* hdb_capability_flags */
 #define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 3a7e2176653..ac47fe78373 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -957,11 +957,16 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 			krb5_clear_error_message(context);
 			goto out;
 		}
-	} else if ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ)) {
+	} else if ((flags & SDB_F_FORCE_CANON) ||
+		   ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ))) {
 		/*
 		 * SDB_F_CANON maps from the canonicalize flag in the
 		 * packet, and has a different meaning between AS-REQ
 		 * and TGS-REQ.  We only change the principal in the AS-REQ case
+		 *
+		 * The SDB_F_FORCE_CANON if for new MIT KDC code that wants
+		 * the canonical name in all lookups, and takes care to
+		 * canonicalize only when appropriate.
 		 */
 		ret = smb_krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
 		if (ret) {
diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 4239332f0d9..53c137de2fd 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -221,6 +221,14 @@ int mit_samba_get_principal(struct mit_samba_context *ctx,
 		return ENOMEM;
 	}
 
+#if KRB5_KDB_API_VERSION >= 10
+	/*
+	 * The MIT KDC code that wants the canonical name in all lookups, and
+	 * takes care to canonicalize only when appropriate.
+	 */
+	sflags |= SDB_F_FORCE_CANON;
+#endif
+
 	if (kflags & KRB5_KDB_FLAG_CANONICALIZE) {
 		sflags |= SDB_F_CANON;
 	}
diff --git a/source4/kdc/sdb.h b/source4/kdc/sdb.h
index c929acccce6..a9115ec23d7 100644
--- a/source4/kdc/sdb.h
+++ b/source4/kdc/sdb.h
@@ -116,6 +116,7 @@ struct sdb_entry_ex {
 #define SDB_F_KVNO_SPECIFIED	128	/* we want a particular KVNO */
 #define SDB_F_FOR_AS_REQ	4096	/* fetch is for a AS REQ */
 #define SDB_F_FOR_TGS_REQ	8192	/* fetch is for a TGS REQ */
+#define SDB_F_FORCE_CANON	16384	/* force canonicalition */
 
 void sdb_free_entry(struct sdb_entry_ex *e);
 void free_sdb_entry(struct sdb_entry *s);
-- 
2.25.1


From f40a974045a34c40f378dd9d96a4d401c3bb9a72 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Tue, 21 Dec 2021 12:17:11 +0100
Subject: [PATCH 20/99] s4:kdc: Also cannoicalize krbtgt principals when
 enforcing canonicalization

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
(cherry picked from commit f1ec950aeb47283a504018bafa21f54c3282e70c)
---
 source4/kdc/db-glue.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index ac47fe78373..d017741e30a 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -920,7 +920,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 	if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
 		p->is_krbtgt = true;
 
-		if (flags & (SDB_F_CANON)) {
+		if (flags & (SDB_F_CANON|SDB_F_FORCE_CANON)) {
 			/*
 			 * When requested to do so, ensure that the
 			 * both realm values in the principal are set
-- 
2.25.1


From 8373345853a59265a9e6d2a826983aa8a4b7a4ea Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 11:30:38 +1300
Subject: [PATCH 21/99] selftest: Check received LDB error code when
 STRICT_CHECKING=0

We were instead only checking the expected error.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit ad4d6fb01fd8083e68f07c427af8932574810cdc)
---
 source4/dsdb/tests/python/priv_attrs.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/dsdb/tests/python/priv_attrs.py b/source4/dsdb/tests/python/priv_attrs.py
index aa35dcc1317..4dfdfb9cbb8 100644
--- a/source4/dsdb/tests/python/priv_attrs.py
+++ b/source4/dsdb/tests/python/priv_attrs.py
@@ -167,7 +167,7 @@ class PrivAttrsTests(samba.tests.TestCase):
         creds_tmp.set_kerberos_state(DONT_USE_KERBEROS)  # kinit is too expensive to use in a tight loop
         return creds_tmp
 
-    def assertGotLdbError(self, got, wanted):
+    def assertGotLdbError(self, wanted, got):
         if not self.strict_checking:
             self.assertNotEqual(got, ldb.SUCCESS)
         else:
-- 
2.25.1


From bc1e71396ad41c37f5fa2101cb5e5e44dc221364 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 11:53:18 +1300
Subject: [PATCH 22/99] tests/krb5: Remove unused variable

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 57b1b76154d699b9d70ad04fa5e94c4b30f0e4bf)
---
 python/samba/tests/krb5/raw_testcase.py | 2 --
 1 file changed, 2 deletions(-)

diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index 42f2e94f5aa..36a6134e6c9 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -2855,7 +2855,6 @@ class RawKerberosTest(TestCaseInTempDir):
 
         expect_etype_info2 = ()
         expect_etype_info = False
-        unexpect_etype_info = True
         expected_aes_type = 0
         expected_rc4_type = 0
         if kcrypto.Enctype.RC4 in proposed_etypes:
@@ -2868,7 +2867,6 @@ class RawKerberosTest(TestCaseInTempDir):
                 if etype > expected_aes_type:
                     expected_aes_type = etype
             if etype in (kcrypto.Enctype.RC4,) and error_code != 0:
-                unexpect_etype_info = False
                 if etype > expected_rc4_type:
                     expected_rc4_type = etype
 
-- 
2.25.1


From 3059417db81edb174da640eb78d4dd6dab5f3120 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 11:34:11 +1300
Subject: [PATCH 23/99] tests/krb5: Deduplicate AS-REQ tests

salt_tests was running the tests defined in the base class as well as
its own tests.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit f0b222e3ecf72c8562bc97bedd9f3a92980b60d5)
---
 python/samba/tests/krb5/as_req_tests.py | 163 ++++++++++++------------
 python/samba/tests/krb5/salt_tests.py   |   4 +-
 2 files changed, 85 insertions(+), 82 deletions(-)

diff --git a/python/samba/tests/krb5/as_req_tests.py b/python/samba/tests/krb5/as_req_tests.py
index 08081928363..315720f85d6 100755
--- a/python/samba/tests/krb5/as_req_tests.py
+++ b/python/samba/tests/krb5/as_req_tests.py
@@ -38,87 +38,8 @@ from samba.tests.krb5.rfc4120_constants import (
 global_asn1_print = False
 global_hexdump = False
 
-@DynamicTestCase
-class AsReqKerberosTests(KDCBaseTest):
-
-    @classmethod
-    def setUpDynamicTestCases(cls):
-        for (name, idx) in cls.etype_test_permutation_name_idx():
-            for pac in [None, True, False]:
-                tname = "%s_pac_%s" % (name, pac)
-                targs = (idx, pac)
-                cls.generate_dynamic_test("test_as_req_no_preauth", tname, *targs)
-
-    def setUp(self):
-        super(AsReqKerberosTests, self).setUp()
-        self.do_asn1_print = global_asn1_print
-        self.do_hexdump = global_hexdump
-
-    def _test_as_req_nopreauth(self,
-                               initial_etypes,
-                               pac=None,
-                               initial_kdc_options=None):
-        client_creds = self.get_client_creds()
-        client_account = client_creds.get_username()
-        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()
-
-        cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
-                                          names=[client_account])
-        sname = self.PrincipalName_create(name_type=NT_SRV_INST,
-                                          names=[krbtgt_account, realm])
-
-        expected_crealm = realm
-        expected_cname = cname
-        expected_srealm = realm
-        expected_sname = sname
-        expected_salt = client_creds.get_salt()
-
-        if any(etype in client_as_etypes and etype in initial_etypes
-               for etype in (kcrypto.Enctype.AES256,
-                             kcrypto.Enctype.AES128,
-                             kcrypto.Enctype.RC4)):
-            expected_error_mode = KDC_ERR_PREAUTH_REQUIRED
-        else:
-            expected_error_mode = KDC_ERR_ETYPE_NOSUPP
-
-        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=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),
-            pac_request=pac)
-
-        self._generic_kdc_exchange(kdc_exchange_dict,
-                                   cname=cname,
-                                   realm=realm,
-                                   sname=sname,
-                                   etypes=initial_etypes)
-
-    def _test_as_req_no_preauth_with_args(self, etype_idx, pac):
-        name, etypes = self.etype_test_permutation_by_idx(etype_idx)
-        self._test_as_req_nopreauth(
-                     pac=pac,
-                     initial_etypes=etypes,
-                     initial_kdc_options=krb5_asn1.KDCOptions('forwardable'))
-
-    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)
 
+class AsReqBaseTest(KDCBaseTest):
     def _run_as_req_enc_timestamp(self, client_creds):
         client_account = client_creds.get_username()
         client_as_etypes = self.get_default_enctypes()
@@ -207,6 +128,88 @@ class AsReqKerberosTests(KDCBaseTest):
         return etype_info2
 
 
+@DynamicTestCase
+class AsReqKerberosTests(AsReqBaseTest):
+
+    @classmethod
+    def setUpDynamicTestCases(cls):
+        for (name, idx) in cls.etype_test_permutation_name_idx():
+            for pac in [None, True, False]:
+                tname = "%s_pac_%s" % (name, pac)
+                targs = (idx, pac)
+                cls.generate_dynamic_test("test_as_req_no_preauth", tname, *targs)
+
+    def setUp(self):
+        super(AsReqKerberosTests, self).setUp()
+        self.do_asn1_print = global_asn1_print
+        self.do_hexdump = global_hexdump
+
+    def _test_as_req_nopreauth(self,
+                               initial_etypes,
+                               pac=None,
+                               initial_kdc_options=None):
+        client_creds = self.get_client_creds()
+        client_account = client_creds.get_username()
+        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()
+
+        cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                          names=[client_account])
+        sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+                                          names=[krbtgt_account, realm])
+
+        expected_crealm = realm
+        expected_cname = cname
+        expected_srealm = realm
+        expected_sname = sname
+        expected_salt = client_creds.get_salt()
+
+        if any(etype in client_as_etypes and etype in initial_etypes
+               for etype in (kcrypto.Enctype.AES256,
+                             kcrypto.Enctype.AES128,
+                             kcrypto.Enctype.RC4)):
+            expected_error_mode = KDC_ERR_PREAUTH_REQUIRED
+        else:
+            expected_error_mode = KDC_ERR_ETYPE_NOSUPP
+
+        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=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),
+            pac_request=pac)
+
+        self._generic_kdc_exchange(kdc_exchange_dict,
+                                   cname=cname,
+                                   realm=realm,
+                                   sname=sname,
+                                   etypes=initial_etypes)
+
+    def _test_as_req_no_preauth_with_args(self, etype_idx, pac):
+        name, etypes = self.etype_test_permutation_by_idx(etype_idx)
+        self._test_as_req_nopreauth(
+                     pac=pac,
+                     initial_etypes=etypes,
+                     initial_kdc_options=krb5_asn1.KDCOptions('forwardable'))
+
+    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)
+
+
 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
index ecbf618e40e..db777f8b7bc 100755
--- a/python/samba/tests/krb5/salt_tests.py
+++ b/python/samba/tests/krb5/salt_tests.py
@@ -21,7 +21,7 @@ import os
 
 import ldb
 
-from samba.tests.krb5.as_req_tests import AsReqKerberosTests
+from samba.tests.krb5.as_req_tests import AsReqBaseTest
 import samba.tests.krb5.kcrypto as kcrypto
 
 sys.path.insert(0, "bin/python")
@@ -31,7 +31,7 @@ global_asn1_print = False
 global_hexdump = False
 
 
-class SaltTests(AsReqKerberosTests):
+class SaltTests(AsReqBaseTest):
 
     def setUp(self):
         super().setUp()
-- 
2.25.1


From 083a777e3d2b18d2e59ee4e04a4387c8db7ec185 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 16:02:00 +1300
Subject: [PATCH 24/99] tests/krb5: Run test_rpc against member server

We were instead always running against the DC.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 167bd2070483004cd0b9a96ffb40ea73c6ddf579)
---
 python/samba/tests/krb5/test_rpc.py | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/python/samba/tests/krb5/test_rpc.py b/python/samba/tests/krb5/test_rpc.py
index 03c125f518a..2d483986e83 100755
--- a/python/samba/tests/krb5/test_rpc.py
+++ b/python/samba/tests/krb5/test_rpc.py
@@ -58,7 +58,7 @@ class RpcTests(KDCBaseTest):
 
         samdb = self.get_samdb()
 
-        mach_name = samdb.host_dns_name()
+        mach_name = self.host
         service = "cifs"
 
         # Create the user account.
@@ -67,7 +67,7 @@ class RpcTests(KDCBaseTest):
             use_cache=False)
         user_name = user_credentials.get_username()
 
-        mach_credentials = self.get_dc_creds()
+        mach_credentials = self.get_server_creds()
 
         # 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
@@ -114,8 +114,7 @@ class RpcTests(KDCBaseTest):
             self.assertEqual(user_name, account_name.string)
 
     def test_rpc_anonymous(self):
-        samdb = self.get_samdb()
-        mach_name = samdb.host_dns_name()
+        mach_name = self.host
 
         anon_creds = credentials.Credentials()
         anon_creds.set_anonymous()
@@ -125,7 +124,7 @@ class RpcTests(KDCBaseTest):
 
         (account_name, _) = conn.GetUserName(None, None, None)
 
-        self.assertEqual('ANONYMOUS LOGON', account_name.string)
+        self.assertEqual('ANONYMOUS LOGON', account_name.string.upper())
 
 
 if __name__ == "__main__":
-- 
2.25.1


From b797f39871100c8d33900af72608d2dc6ec9f435 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 11:37:35 +1300
Subject: [PATCH 25/99] tests/krb5: Allow PasswordKey_create() to use s2kparams

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit a560c2e9ad8abb824d1805c86c656943745f81eb)
---
 python/samba/tests/krb5/raw_testcase.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index 36a6134e6c9..da3f69c79c6 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -1167,10 +1167,11 @@ class RawKerberosTest(TestCaseInTempDir):
         key = kcrypto.Key(etype, contents)
         return RodcPacEncryptionKey(key, kvno)
 
-    def PasswordKey_create(self, etype=None, pwd=None, salt=None, kvno=None):
+    def PasswordKey_create(self, etype=None, pwd=None, salt=None, kvno=None,
+                           params=None):
         self.assertIsNotNone(pwd)
         self.assertIsNotNone(salt)
-        key = kcrypto.string_to_key(etype, pwd, salt)
+        key = kcrypto.string_to_key(etype, pwd, salt, params=params)
         return RodcPacEncryptionKey(key, kvno)
 
     def PasswordKey_from_etype_info2(self, creds, etype_info2, kvno=None):
@@ -1182,9 +1183,11 @@ class RawKerberosTest(TestCaseInTempDir):
             nthash = creds.get_nt_hash()
             return self.SessionKey_create(etype=e, contents=nthash, kvno=kvno)
 
+        params = etype_info2.get('s2kparams')
+
         password = creds.get_password()
         return self.PasswordKey_create(
-            etype=e, pwd=password, salt=salt, kvno=kvno)
+            etype=e, pwd=password, salt=salt, kvno=kvno, params=params)
 
     def TicketDecryptionKey_from_creds(self, creds, etype=None):
 
-- 
2.25.1


From 9fbb213304ecebac5b7620b8f183a5baddeb287d Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 11:40:35 +1300
Subject: [PATCH 26/99] tests/krb5: Split out methods to create renewable or
 invalid tickets

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit e930274aa43810d6485c3c8a7c82958ecb409630)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 68 +++++++++++++-----------
 1 file changed, 36 insertions(+), 32 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index abac5a47a56..0578969ba69 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -1786,6 +1786,40 @@ class KdcTgsTests(KDCBaseTest):
 
         self._run_tgs(tgt, expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN)
 
+    def _modify_renewable(self, enc_part):
+        # Set the renewable flag.
+        renewable_flag = krb5_asn1.TicketFlags('renewable')
+        pos = len(tuple(renewable_flag)) - 1
+
+        flags = enc_part['flags']
+        self.assertLessEqual(pos, len(flags))
+
+        new_flags = flags[:pos] + '1' + flags[pos + 1:]
+        enc_part['flags'] = new_flags
+
+        # Set the renew-till time to be in the future.
+        renew_till = self.get_KerberosTime(offset=100 * 60 * 60)
+        enc_part['renew-till'] = renew_till
+
+        return enc_part
+
+    def _modify_invalid(self, enc_part):
+        # Set the invalid flag.
+        invalid_flag = krb5_asn1.TicketFlags('invalid')
+        pos = len(tuple(invalid_flag)) - 1
+
+        flags = enc_part['flags']
+        self.assertLessEqual(pos, len(flags))
+
+        new_flags = flags[:pos] + '1' + flags[pos + 1:]
+        enc_part['flags'] = new_flags
+
+        # Set the ticket start time to be in the past.
+        past_time = self.get_KerberosTime(offset=-100 * 60 * 60)
+        enc_part['starttime'] = past_time
+
+        return enc_part
+
     def _get_tgt(self,
                  client_creds,
                  renewable=False,
@@ -1880,39 +1914,9 @@ class KdcTgsTests(KDCBaseTest):
             }
 
         if renewable:
-            def flags_modify_fn(enc_part):
-                # Set the renewable flag.
-                renewable_flag = krb5_asn1.TicketFlags('renewable')
-                pos = len(tuple(renewable_flag)) - 1
-
-                flags = enc_part['flags']
-                self.assertLessEqual(pos, len(flags))
-
-                new_flags = flags[:pos] + '1' + flags[pos + 1:]
-                enc_part['flags'] = new_flags
-
-                # Set the renew-till time to be in the future.
-                renew_till = self.get_KerberosTime(offset=100 * 60 * 60)
-                enc_part['renew-till'] = renew_till
-
-                return enc_part
+            flags_modify_fn = self._modify_renewable
         elif invalid:
-            def flags_modify_fn(enc_part):
-                # Set the invalid flag.
-                invalid_flag = krb5_asn1.TicketFlags('invalid')
-                pos = len(tuple(invalid_flag)) - 1
-
-                flags = enc_part['flags']
-                self.assertLessEqual(pos, len(flags))
-
-                new_flags = flags[:pos] + '1' + flags[pos + 1:]
-                enc_part['flags'] = new_flags
-
-                # Set the ticket start time to be in the past.
-                past_time = self.get_KerberosTime(offset=-100 * 60 * 60)
-                enc_part['starttime'] = past_time
-
-                return enc_part
+            flags_modify_fn = self._modify_invalid
         else:
             flags_modify_fn = None
 
-- 
2.25.1


From 9d8786faa9fa6ca1182ec2b382882361a588f54d Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 11:52:31 +1300
Subject: [PATCH 27/99] tests/krb5: Adjust error codes to better match Windows
 with PacRequestorEnforcement=2

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit d95705172bcf6fe24817800a4c0009e9cc8be595)
---
 python/samba/tests/krb5/alias_tests.py        |   7 +-
 python/samba/tests/krb5/kdc_tgs_tests.py      | 130 ++++++++----------
 .../ms_kile_client_principal_lookup_tests.py  |  39 ++----
 python/samba/tests/krb5/s4u_tests.py          |  57 ++++----
 python/samba/tests/krb5/test_rpc.py           |   8 +-
 selftest/knownfail_heimdal_kdc                |  64 +++++++++
 selftest/knownfail_mit_kdc                    |  11 ++
 7 files changed, 183 insertions(+), 133 deletions(-)

diff --git a/python/samba/tests/krb5/alias_tests.py b/python/samba/tests/krb5/alias_tests.py
index 60213845a44..1f63775c189 100755
--- a/python/samba/tests/krb5/alias_tests.py
+++ b/python/samba/tests/krb5/alias_tests.py
@@ -28,7 +28,7 @@ from samba.tests.krb5.kdc_base_test import KDCBaseTest
 from samba.tests.krb5.rfc4120_constants import (
     AES256_CTS_HMAC_SHA1_96,
     ARCFOUR_HMAC_MD5,
-    KDC_ERR_CLIENT_NAME_MISMATCH,
+    KDC_ERR_TGT_REVOKED,
     NT_PRINCIPAL,
 )
 
@@ -168,7 +168,7 @@ class AliasTests(KDCBaseTest):
                                              ctype=None)
             return [padata], req_body
 
-        expected_error_mode = KDC_ERR_CLIENT_NAME_MISMATCH
+        expected_error_mode = KDC_ERR_TGT_REVOKED
 
         # Make a request using S4U2Self. The request should fail.
         kdc_exchange_dict = self.tgs_exchange_dict(
@@ -184,7 +184,8 @@ class AliasTests(KDCBaseTest):
             tgt=tgt,
             authenticator_subkey=authenticator_subkey,
             kdc_options='0',
-            expect_pac=True)
+            expect_pac=True,
+            expect_edata=False)
 
         rep = self._generic_kdc_exchange(kdc_exchange_dict,
                                          cname=None,
diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 0578969ba69..7ea15f0fbab 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -23,7 +23,7 @@ import os
 import ldb
 
 
-from samba import dsdb, ntstatus
+from samba import dsdb
 
 from samba.dcerpc import krb5pac, security
 
@@ -38,8 +38,6 @@ from samba.tests.krb5.rfc4120_constants import (
     KRB_ERROR,
     KRB_TGS_REP,
     KDC_ERR_BADMATCH,
-    KDC_ERR_BADOPTION,
-    KDC_ERR_CLIENT_NAME_MISMATCH,
     KDC_ERR_GENERIC,
     KDC_ERR_MODIFIED,
     KDC_ERR_POLICY,
@@ -262,7 +260,7 @@ class KdcTgsTests(KDCBaseTest):
         authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
 
         if expect_error:
-            expected_error_mode = KDC_ERR_BADOPTION
+            expected_error_mode = KDC_ERR_TGT_REVOKED
             check_error_fn = self.generic_check_kdc_error
             check_rep_fn = None
         else:
@@ -288,7 +286,8 @@ class KdcTgsTests(KDCBaseTest):
             authenticator_subkey=authenticator_subkey,
             kdc_options=kdc_options,
             pac_request=pac_request,
-            expect_pac=expect_pac)
+            expect_pac=expect_pac,
+            expect_edata=False)
 
         rep = self._generic_kdc_exchange(kdc_exchange_dict,
                                          cname=cname,
@@ -516,8 +515,7 @@ class KdcTgsTests(KDCBaseTest):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_requester_sid=True)
 
-        self._run_tgs(tgt, expected_error=0, expect_pac=True,
-                      expect_requester_sid=False)  # Note: not expected
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_req_no_pac_attrs(self):
         creds = self._get_creds()
@@ -531,11 +529,7 @@ class KdcTgsTests(KDCBaseTest):
                                 revealed_to_rodc=True)
         tgt = self._get_tgt(creds, from_rodc=True, remove_requester_sid=True)
 
-        samdb = self.get_samdb()
-        sid = self.get_objectSid(samdb, creds.get_dn())
-
-        self._run_tgs(tgt, expected_error=0, expect_pac=True,
-                      expect_requester_sid=True, expected_sid=sid)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_req_from_rodc_no_pac_attrs(self):
         creds = self._get_creds(replication_allowed=True,
@@ -548,101 +542,99 @@ class KdcTgsTests(KDCBaseTest):
     def test_tgs_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_pac=True)
-        self._run_tgs(tgt, expected_error=KDC_ERR_BADOPTION)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_renew_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, renewable=True, remove_pac=True)
-        self._renew_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_validate_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, invalid=True, remove_pac=True)
-        self._validate_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_s4u2self_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_pac=True)
         self._s4u2self(tgt, creds,
-                       expected_error=(KDC_ERR_GENERIC, KDC_ERR_BADOPTION),
-                       expected_status=ntstatus.NT_STATUS_INVALID_PARAMETER,
-                       expect_edata=True)
+                       expected_error=KDC_ERR_TGT_REVOKED,
+                       expect_edata=False)
 
     def test_user2user_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_pac=True)
-        self._user2user(tgt, creds, expected_error=KDC_ERR_BADOPTION)
+        self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
     # Test making a request with authdata and without a PAC.
     def test_tgs_authdata_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
-        self._run_tgs(tgt, expected_error=KDC_ERR_BADOPTION)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_renew_authdata_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, renewable=True, remove_pac=True,
                             allow_empty_authdata=True)
-        self._renew_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_validate_authdata_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, invalid=True, remove_pac=True,
                             allow_empty_authdata=True)
-        self._validate_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_s4u2self_authdata_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
         self._s4u2self(tgt, creds,
-                       expected_error=(KDC_ERR_GENERIC, KDC_ERR_BADOPTION),
-                       expected_status=ntstatus.NT_STATUS_INVALID_PARAMETER,
-                       expect_edata=True)
+                       expected_error=KDC_ERR_TGT_REVOKED,
+                       expect_edata=False)
 
     def test_user2user_authdata_no_pac(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
-        self._user2user(tgt, creds, expected_error=KDC_ERR_BADOPTION)
+        self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
     # Test changing the SID in the PAC to that of another account.
     def test_tgs_sid_mismatch_existing(self):
         creds = self._get_creds()
         existing_rid = self._get_existing_rid()
         tgt = self._get_tgt(creds, new_rid=existing_rid)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_renew_sid_mismatch_existing(self):
         creds = self._get_creds()
         existing_rid = self._get_existing_rid()
         tgt = self._get_tgt(creds, renewable=True, new_rid=existing_rid)
-        self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_validate_sid_mismatch_existing(self):
         creds = self._get_creds()
         existing_rid = self._get_existing_rid()
         tgt = self._get_tgt(creds, invalid=True, new_rid=existing_rid)
-        self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_s4u2self_sid_mismatch_existing(self):
         creds = self._get_creds()
         existing_rid = self._get_existing_rid()
         tgt = self._get_tgt(creds, new_rid=existing_rid)
         self._s4u2self(tgt, creds,
-                       expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+                       expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_user2user_sid_mismatch_existing(self):
         creds = self._get_creds()
         existing_rid = self._get_existing_rid()
         tgt = self._get_tgt(creds, new_rid=existing_rid)
         self._user2user(tgt, creds,
-                        expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+                        expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_requester_sid_mismatch_existing(self):
         creds = self._get_creds()
         existing_rid = self._get_existing_rid()
         tgt = self._get_tgt(creds, new_rid=existing_rid,
                             can_modify_logon_info=False)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_logon_info_sid_mismatch_existing(self):
         creds = self._get_creds()
@@ -656,49 +648,49 @@ class KdcTgsTests(KDCBaseTest):
         existing_rid = self._get_existing_rid()
         tgt = self._get_tgt(creds, new_rid=existing_rid,
                             remove_requester_sid=True)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     # Test changing the SID in the PAC to a non-existent one.
     def test_tgs_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, new_rid=nonexistent_rid)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_renew_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, renewable=True,
                             new_rid=nonexistent_rid)
-        self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_validate_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, invalid=True,
                             new_rid=nonexistent_rid)
-        self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_s4u2self_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, new_rid=nonexistent_rid)
         self._s4u2self(tgt, creds,
-                       expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+                       expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_user2user_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, new_rid=nonexistent_rid)
         self._user2user(tgt, creds,
-                        expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+                        expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_requester_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, new_rid=nonexistent_rid,
                             can_modify_logon_info=False)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_logon_info_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
@@ -712,7 +704,7 @@ class KdcTgsTests(KDCBaseTest):
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, new_rid=nonexistent_rid,
                             remove_requester_sid=True)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     # Test with an RODC-issued ticket where the client is revealed to the RODC.
     def test_tgs_rodc_revealed(self):
@@ -753,7 +745,7 @@ class KdcTgsTests(KDCBaseTest):
         existing_rid = self._get_existing_rid(replication_allowed=True,
                                               revealed_to_rodc=True)
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_renew_rodc_sid_mismatch_existing(self):
         creds = self._get_creds(replication_allowed=True,
@@ -762,7 +754,7 @@ class KdcTgsTests(KDCBaseTest):
                                               revealed_to_rodc=True)
         tgt = self._get_tgt(creds, renewable=True, from_rodc=True,
                             new_rid=existing_rid)
-        self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_validate_rodc_sid_mismatch_existing(self):
         creds = self._get_creds(replication_allowed=True,
@@ -771,7 +763,7 @@ class KdcTgsTests(KDCBaseTest):
                                        revealed_to_rodc=True)
         tgt = self._get_tgt(creds, invalid=True, from_rodc=True,
                             new_rid=existing_rid)
-        self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_s4u2self_rodc_sid_mismatch_existing(self):
         creds = self._get_creds(replication_allowed=True,
@@ -779,7 +771,7 @@ class KdcTgsTests(KDCBaseTest):
         existing_rid = self._get_existing_rid(replication_allowed=True,
                                               revealed_to_rodc=True)
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid)
-        self._s4u2self(tgt, creds, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_user2user_rodc_sid_mismatch_existing(self):
         creds = self._get_creds(replication_allowed=True,
@@ -788,7 +780,7 @@ class KdcTgsTests(KDCBaseTest):
                                               revealed_to_rodc=True)
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid)
         self._user2user(tgt, creds,
-                        expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+                        expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_rodc_requester_sid_mismatch_existing(self):
         creds = self._get_creds(replication_allowed=True,
@@ -797,7 +789,7 @@ class KdcTgsTests(KDCBaseTest):
                                               revealed_to_rodc=True)
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid,
                             can_modify_logon_info=False)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_rodc_logon_info_sid_mismatch_existing(self):
         creds = self._get_creds(replication_allowed=True,
@@ -815,7 +807,7 @@ class KdcTgsTests(KDCBaseTest):
                                               revealed_to_rodc=True)
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid,
                             remove_requester_sid=True)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     # Test with an RODC-issued ticket where the SID in the PAC is changed to a
     # non-existent one.
@@ -824,7 +816,7 @@ class KdcTgsTests(KDCBaseTest):
                                 revealed_to_rodc=True)
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_renew_rodc_sid_mismatch_nonexisting(self):
         creds = self._get_creds(replication_allowed=True,
@@ -832,7 +824,7 @@ class KdcTgsTests(KDCBaseTest):
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, renewable=True, from_rodc=True,
                             new_rid=nonexistent_rid)
-        self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_validate_rodc_sid_mismatch_nonexisting(self):
         creds = self._get_creds(replication_allowed=True,
@@ -840,14 +832,14 @@ class KdcTgsTests(KDCBaseTest):
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, invalid=True, from_rodc=True,
                             new_rid=nonexistent_rid)
-        self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_s4u2self_rodc_sid_mismatch_nonexisting(self):
         creds = self._get_creds(replication_allowed=True,
                                 revealed_to_rodc=True)
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid)
-        self._s4u2self(tgt, creds, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_user2user_rodc_sid_mismatch_nonexisting(self):
         creds = self._get_creds(replication_allowed=True,
@@ -855,7 +847,7 @@ class KdcTgsTests(KDCBaseTest):
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid)
         self._user2user(tgt, creds,
-                        expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+                        expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_rodc_requester_sid_mismatch_nonexisting(self):
         creds = self._get_creds(replication_allowed=True,
@@ -863,7 +855,7 @@ class KdcTgsTests(KDCBaseTest):
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid,
                             can_modify_logon_info=False)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_rodc_logon_info_sid_mismatch_nonexisting(self):
         creds = self._get_creds(replication_allowed=True,
@@ -879,7 +871,7 @@ class KdcTgsTests(KDCBaseTest):
         nonexistent_rid = self._get_non_existent_rid()
         tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid,
                             remove_requester_sid=True)
-        self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+        self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     # Test with an RODC-issued ticket where the client is not revealed to the
     # RODC.
@@ -1111,8 +1103,7 @@ class KdcTgsTests(KDCBaseTest):
                                           names=[user_name])
 
         self._user2user(tgt, creds, sname=sname,
-                        expected_error=(KDC_ERR_BADMATCH,
-                                        KDC_ERR_BADOPTION))
+                        expected_error=KDC_ERR_BADMATCH)
 
     def test_user2user_other_sname(self):
         other_name = self.get_new_username()
@@ -1134,8 +1125,7 @@ class KdcTgsTests(KDCBaseTest):
         sname = self.get_krbtgt_sname()
 
         self._user2user(tgt, creds, sname=sname,
-                        expected_error=(KDC_ERR_BADMATCH,
-                                        KDC_ERR_BADOPTION))
+                        expected_error=KDC_ERR_BADMATCH)
 
     def test_user2user_wrong_srealm(self):
         creds = self._get_creds()
@@ -1206,7 +1196,9 @@ class KdcTgsTests(KDCBaseTest):
 
         tgt = self._modify_tgt(tgt, cname=cname)
 
-        self._user2user(tgt, creds, expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN)
+        self._user2user(tgt, creds,
+                        expected_error=(KDC_ERR_TGT_REVOKED,
+                                        KDC_ERR_C_PRINCIPAL_UNKNOWN))
 
     def test_user2user_non_existent_sname(self):
         creds = self._get_creds()
@@ -1522,8 +1514,7 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._modify_tgt(tgt, renewable=True,
                                remove_requester_sid=True)
 
-        self._renew_tgt(tgt, expected_error=0, expect_pac=True,
-                        expect_requester_sid=False)  # Note: not expected
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_requester_sid_missing_rodc_renew(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1539,9 +1530,7 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True,
                                remove_requester_sid=True)
 
-        self._renew_tgt(tgt, expected_error=0, expect_pac=True,
-                        expected_sid=sid,
-                        expect_requester_sid=True)
+        self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
     def test_tgs_pac_request_none(self):
         creds = self._get_creds()
@@ -1655,10 +1644,10 @@ class KdcTgsTests(KDCBaseTest):
         creds = self._get_creds()
         tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
 
-        ticket = self._s4u2self(tgt, creds, expected_error=0, expect_pac=False)
+        ticket = self._s4u2self(tgt, creds, expected_error=0, expect_pac=True)
 
-        pac = self.get_ticket_pac(ticket, expect_pac=False)
-        self.assertIsNone(pac)
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
 
     def test_s4u2self_pac_request_true(self):
         creds = self._get_creds()
@@ -1753,10 +1742,10 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
         tgt = self._modify_tgt(tgt, from_rodc=True)
 
-        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=False)
+        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
 
         pac = self.get_ticket_pac(ticket, expect_pac=False)
-        self.assertIsNone(pac)
+        self.assertIsNotNone(pac)
 
     def test_tgs_rodc_pac_request_true(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1784,7 +1773,8 @@ class KdcTgsTests(KDCBaseTest):
                                                    'sAMAccountName')
         samdb.modify(msg)
 
-        self._run_tgs(tgt, expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN)
+        self._run_tgs(tgt, expected_error=(KDC_ERR_TGT_REVOKED,
+                                           KDC_ERR_C_PRINCIPAL_UNKNOWN))
 
     def _modify_renewable(self, enc_part):
         # Set the renewable flag.
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 0aa3309b814..e6b90d3e16a 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
@@ -32,6 +32,7 @@ from samba.tests.krb5.rfc4120_constants import (
     NT_PRINCIPAL,
     NT_SRV_INST,
     KDC_ERR_C_PRINCIPAL_UNKNOWN,
+    KDC_ERR_TGT_REVOKED,
 )
 
 global_asn1_print = False
@@ -322,21 +323,10 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest):
 
         (rep, enc_part) = self.tgs_req(
             cname, sname, uc.get_realm(), ticket, key, etype,
-            service_creds=mc, expect_pac=False)
-        self.check_tgs_reply(rep)
-
-        # Check the contents of the service ticket
-        ticket = rep['ticket']
-        enc_part = self.decode_service_ticket(mc, ticket)
-        #
-        # We get an empty authorization-data element in the ticket.
-        # i.e. no PAC
-        self.assertEqual([], enc_part['authorization-data'])
-        # check the crealm and cname
-        cname = enc_part['cname']
-        self.assertEqual(NT_PRINCIPAL, cname['name-type'])
-        self.assertEqual(alt_name.encode('UTF8'), cname['name-string'][0])
-        self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+            service_creds=mc, expect_pac=False,
+            expect_edata=False,
+            expected_error_mode=KDC_ERR_TGT_REVOKED)
+        self.check_error_rep(rep, KDC_ERR_TGT_REVOKED)
 
     def test_nt_principal_step_4_b(self):
         ''' Step 4, pre-authentication
@@ -703,21 +693,10 @@ class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest):
 
         (rep, enc_part) = self.tgs_req(
             cname, sname, uc.get_realm(), ticket, key, etype,
-            service_creds=mc, expect_pac=False)
-        self.check_tgs_reply(rep)
-
-        # Check the contents of the service ticket
-        ticket = rep['ticket']
-        enc_part = self.decode_service_ticket(mc, ticket)
-        #
-        # We get an empty authorization-data element in the ticket.
-        # i.e. no PAC
-        self.assertEqual([], enc_part['authorization-data'])
-        # check the crealm and cname
-        cname = enc_part['cname']
-        self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
-        self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
-        self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+            service_creds=mc, expect_pac=False,
+            expect_edata=False,
+            expected_error_mode=KDC_ERR_TGT_REVOKED)
+        self.check_error_rep(rep, KDC_ERR_TGT_REVOKED)
 
     def test_nt_enterprise_principal_step_6_b(self):
         ''' Step 4, pre-authentication
diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py
index a80a7b3427e..5f37525f393 100755
--- a/python/samba/tests/krb5/s4u_tests.py
+++ b/python/samba/tests/krb5/s4u_tests.py
@@ -42,6 +42,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KDC_ERR_INAPP_CKSUM,
     KDC_ERR_MODIFIED,
     KDC_ERR_SUMTYPE_NOSUPP,
+    KDC_ERR_TGT_REVOKED,
     KU_PA_ENC_TIMESTAMP,
     KU_AS_REP_ENC_PART,
     KU_TGS_REP_ENC_PART_SUB_KEY,
@@ -278,6 +279,8 @@ class S4UKerberosTests(KDCBaseTest):
         etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96,
                                          ARCFOUR_HMAC_MD5))
 
+        expect_edata = kdc_dict.pop('expect_edata', None)
+
         def generate_s4u2self_padata(_kdc_exchange_dict,
                                      _callback_dict,
                                      req_body):
@@ -309,7 +312,8 @@ class S4UKerberosTests(KDCBaseTest):
             tgt=service_tgt,
             authenticator_subkey=authenticator_subkey,
             kdc_options=str(kdc_options),
-            expect_claims=False)
+            expect_claims=False,
+            expect_edata=expect_edata)
 
         self._generic_kdc_exchange(kdc_exchange_dict,
                                    cname=None,
@@ -343,15 +347,14 @@ class S4UKerberosTests(KDCBaseTest):
 
         self._run_s4u2self_test(
             {
-                'expected_error_mode': (KDC_ERR_GENERIC,
-                                        KDC_ERR_BADOPTION),
-                'expected_status': ntstatus.NT_STATUS_INVALID_PARAMETER,
+                'expected_error_mode': KDC_ERR_TGT_REVOKED,
                 'client_opts': {
                     'not_delegated': False
                 },
                 'kdc_options': 'forwardable',
                 'modify_service_tgt_fn': forwardable_no_pac,
-                'expected_flags': 'forwardable'
+                'expected_flags': 'forwardable',
+                'expect_edata': False
             })
 
     # Test performing an S4U2Self operation without requesting a forwardable
@@ -674,8 +677,8 @@ class S4UKerberosTests(KDCBaseTest):
         # contain a PAC.
         self._run_delegation_test(
             {
-                'expected_error_mode': (KDC_ERR_BADOPTION,
-                                        KDC_ERR_MODIFIED),
+                'expected_error_mode': (KDC_ERR_MODIFIED,
+                                        KDC_ERR_TGT_REVOKED),
                 'allow_delegation': True,
                 'modify_client_tkt_fn': self.remove_ticket_pac,
                 'expect_edata': False
@@ -686,9 +689,10 @@ class S4UKerberosTests(KDCBaseTest):
         # PAC.
         self._run_delegation_test(
             {
-                'expected_error_mode': 0,
+                'expected_error_mode': KDC_ERR_TGT_REVOKED,
                 'allow_delegation': True,
-                'modify_service_tgt_fn': self.remove_ticket_pac
+                'modify_service_tgt_fn': self.remove_ticket_pac,
+                'expect_edata': False
             })
 
     def test_constrained_delegation_no_client_pac_no_auth_data_required(self):
@@ -696,8 +700,8 @@ class S4UKerberosTests(KDCBaseTest):
         # contain a PAC.
         self._run_delegation_test(
             {
-                'expected_error_mode': (KDC_ERR_BADOPTION,
-                                        KDC_ERR_MODIFIED),
+                'expected_error_mode': (KDC_ERR_MODIFIED,
+                                        KDC_ERR_BADOPTION),
                 'allow_delegation': True,
                 'modify_client_tkt_fn': self.remove_ticket_pac,
                 'expect_edata': False,
@@ -711,13 +715,14 @@ class S4UKerberosTests(KDCBaseTest):
         # PAC.
         self._run_delegation_test(
             {
-                'expected_error_mode': (KDC_ERR_BADOPTION,
-                                        KDC_ERR_MODIFIED),
+                'expected_error_mode': KDC_ERR_TGT_REVOKED,
                 'allow_delegation': True,
                 'modify_service_tgt_fn': self.remove_ticket_pac,
                 'service2_opts': {
                     'no_auth_data_required': True
-                }
+                },
+                'expect_pac': False,
+                'expect_edata': False
             })
 
     def test_constrained_delegation_non_forwardable(self):
@@ -812,12 +817,11 @@ class S4UKerberosTests(KDCBaseTest):
         # PAC.
         self._run_delegation_test(
             {
-                'expected_error_mode': KDC_ERR_BADOPTION,
-                'expected_status':
-                    ntstatus.NT_STATUS_NOT_FOUND,
+                'expected_error_mode': KDC_ERR_TGT_REVOKED,
                 'allow_rbcd': True,
                 'pac_options': '0001',  # supports RBCD
-                'modify_service_tgt_fn': self.remove_ticket_pac
+                'modify_service_tgt_fn': self.remove_ticket_pac,
+                'expect_edata': False
             })
 
     def test_rbcd_no_client_pac_no_auth_data_required_a(self):
@@ -858,15 +862,14 @@ class S4UKerberosTests(KDCBaseTest):
         # PAC.
         self._run_delegation_test(
             {
-                'expected_error_mode': KDC_ERR_BADOPTION,
-                'expected_status':
-                    ntstatus.NT_STATUS_NOT_FOUND,
+                'expected_error_mode': KDC_ERR_TGT_REVOKED,
                 'allow_rbcd': True,
                 'pac_options': '0001',  # supports RBCD
                 'modify_service_tgt_fn': self.remove_ticket_pac,
                 'service2_opts': {
                     'no_auth_data_required': True
-                }
+                },
+                'expect_edata': False
             })
 
     def test_rbcd_non_forwardable(self):
@@ -941,8 +944,8 @@ class S4UKerberosTests(KDCBaseTest):
         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)
+                    expected_error_mode = (KDC_ERR_MODIFIED,
+                                           KDC_ERR_BADOPTION)
                 else:
                     expected_error_mode = KDC_ERR_GENERIC
 
@@ -1061,8 +1064,7 @@ class S4UKerberosTests(KDCBaseTest):
         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_error_mode = KDC_ERR_MODIFIED
                     expected_status = ntstatus.NT_STATUS_WRONG_PASSWORD
                 else:
                     expected_error_mode = 0
@@ -1162,8 +1164,7 @@ class S4UKerberosTests(KDCBaseTest):
                 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_error_mode = KDC_ERR_SUMTYPE_NOSUPP
                             expected_status = ntstatus.NT_STATUS_LOGON_FAILURE
                         else:
                             expected_error_mode = KDC_ERR_GENERIC
diff --git a/python/samba/tests/krb5/test_rpc.py b/python/samba/tests/krb5/test_rpc.py
index 2d483986e83..5a3c7339cea 100755
--- a/python/samba/tests/krb5/test_rpc.py
+++ b/python/samba/tests/krb5/test_rpc.py
@@ -24,7 +24,10 @@ import ldb
 
 from samba import NTSTATUSError, credentials
 from samba.dcerpc import lsa
-from samba.ntstatus import NT_STATUS_NO_IMPERSONATION_TOKEN
+from samba.ntstatus import (
+    NT_STATUS_ACCESS_DENIED,
+    NT_STATUS_NO_IMPERSONATION_TOKEN
+)
 
 from samba.tests.krb5.kdc_base_test import KDCBaseTest
 
@@ -103,7 +106,8 @@ class RpcTests(KDCBaseTest):
                 self.fail()
 
             enum, _ = e.args
-            self.assertEqual(NT_STATUS_NO_IMPERSONATION_TOKEN, enum)
+            self.assertIn(enum, {NT_STATUS_ACCESS_DENIED,
+                                 NT_STATUS_NO_IMPERSONATION_TOKEN})
             return
 
         (account_name, _) = conn.GetUserName(None, None, None)
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 0f62627ae31..cfbe698fb15 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -71,16 +71,21 @@
 # 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_client_pac(?!_no_auth_data_required)
 ^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_no_auth_data_required
 ^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_no_service_pac
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_service_pac_no_auth_data_required
 ^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_forwardable
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_no_pac
 ^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_constrained_delegation_no_auth_data_required
@@ -97,3 +102,62 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed
+#
+# Alias tests
+#
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_delete
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_rename
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_delete
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_rename
+#
+# KDC TGS tests
+#
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_nonexisting
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index c046a46a4f3..31010c16391 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -368,6 +368,8 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 #
 # KDC TGT tests
 #
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied
@@ -379,6 +381,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_renew_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied
@@ -394,6 +400,7 @@ 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_tgs_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rename
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_krbtgt_link
@@ -403,6 +410,8 @@ 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_tgs_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_sname
@@ -432,6 +441,8 @@ 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_validate_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_nonexisting
 #
 # PAC attributes tests
 #
-- 
2.25.1


From 011a468c786bac72ce8ad40544ffa7798fa38a97 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 12:04:36 +1300
Subject: [PATCH 28/99] tests/krb5: Remove unnecessary expect_pac arguments

The value of expect_pac is not considered if we are expecting an error.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 28d501875a98fa2817262eb8ec68bf91528428c2)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 7ea15f0fbab..6160ef649e8 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -412,7 +412,7 @@ class KdcTgsTests(KDCBaseTest):
         self.assertIsNone(pac)
 
         self._make_tgs_request(client_creds, service_creds, tgt,
-                               expect_pac=False, expect_error=True)
+                               expect_error=True)
 
     def test_remove_pac_client_no_auth_data_required(self):
         client_creds = self.get_cached_creds(
@@ -427,7 +427,7 @@ class KdcTgsTests(KDCBaseTest):
         self.assertIsNone(pac)
 
         self._make_tgs_request(client_creds, service_creds, tgt,
-                               expect_pac=False, expect_error=True)
+                               expect_error=True)
 
     def test_remove_pac(self):
         client_creds = self.get_client_creds()
@@ -440,7 +440,7 @@ class KdcTgsTests(KDCBaseTest):
         self.assertIsNone(pac)
 
         self._make_tgs_request(client_creds, service_creds, tgt,
-                               expect_pac=False, expect_error=True)
+                               expect_error=True)
 
     def test_upn_dns_info_ex_user(self):
         client_creds = self.get_client_creds()
-- 
2.25.1


From a696ddc90a9f31997478620807c7a4991fc851ab Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 30 Nov 2021 09:26:40 +1300
Subject: [PATCH 29/99] tests/krb5: Add tests for invalid TGTs

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 7574ba9f580fca552b80532a49d00e657fbdf4fd)
---
 python/samba/tests/krb5/kdc_tgs_tests.py     | 16 ++++++++++++++++
 python/samba/tests/krb5/rfc4120_constants.py |  1 +
 selftest/knownfail_mit_kdc                   |  3 ++-
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 6160ef649e8..f5f091610ac 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -44,6 +44,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KDC_ERR_C_PRINCIPAL_UNKNOWN,
     KDC_ERR_S_PRINCIPAL_UNKNOWN,
     KDC_ERR_TGT_REVOKED,
+    KRB_ERR_TKT_NYV,
     KDC_ERR_WRONG_REALM,
     NT_PRINCIPAL,
     NT_SRV_INST,
@@ -511,6 +512,21 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds)
         self._user2user(tgt, creds, expected_error=0)
 
+    def test_tgs_req_invalid(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds, invalid=True)
+        self._run_tgs(tgt, expected_error=KRB_ERR_TKT_NYV)
+
+    def test_s4u2self_req_invalid(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds, invalid=True)
+        self._s4u2self(tgt, creds, expected_error=KRB_ERR_TKT_NYV)
+
+    def test_user2user_req_invalid(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds, invalid=True)
+        self._user2user(tgt, creds, expected_error=KRB_ERR_TKT_NYV)
+
     def test_tgs_req_no_requester_sid(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_requester_sid=True)
diff --git a/python/samba/tests/krb5/rfc4120_constants.py b/python/samba/tests/krb5/rfc4120_constants.py
index 5251e291fde..a9fdc5735dd 100644
--- a/python/samba/tests/krb5/rfc4120_constants.py
+++ b/python/samba/tests/krb5/rfc4120_constants.py
@@ -76,6 +76,7 @@ KDC_ERR_TGT_REVOKED = 20
 KDC_ERR_PREAUTH_FAILED = 24
 KDC_ERR_PREAUTH_REQUIRED = 25
 KDC_ERR_BAD_INTEGRITY = 31
+KRB_ERR_TKT_NYV = 33
 KDC_ERR_NOT_US = 35
 KDC_ERR_BADMATCH = 36
 KDC_ERR_SKEW = 37
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 31010c16391..2aa7fb2b370 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -385,7 +385,7 @@ 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_renew_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req(?!_invalid)
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_krbtgt_link
@@ -415,6 +415,7 @@ 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_user2user_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_sname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_req_invalid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_krbtgt_link
-- 
2.25.1


From 7197641eda7ba738cfcce40d43314588c6474251 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 12:10:45 +1300
Subject: [PATCH 30/99] tests/krb5: Add tests for TGS requests with a non-TGT

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 778029c1dc443b87f4ed4b9d2c613d0e6fc45b0d)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 51 ++++++++++++++++++++++++
 selftest/knownfail_mit_kdc               |  2 +
 2 files changed, 53 insertions(+)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index f5f091610ac..52297c963e8 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -40,6 +40,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KDC_ERR_BADMATCH,
     KDC_ERR_GENERIC,
     KDC_ERR_MODIFIED,
+    KDC_ERR_NOT_US,
     KDC_ERR_POLICY,
     KDC_ERR_C_PRINCIPAL_UNKNOWN,
     KDC_ERR_S_PRINCIPAL_UNKNOWN,
@@ -1234,6 +1235,56 @@ class KdcTgsTests(KDCBaseTest):
                         expected_error=(KDC_ERR_GENERIC,
                                         KDC_ERR_S_PRINCIPAL_UNKNOWN))
 
+    def test_tgs_service_ticket(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds)
+
+        service_creds = self.get_service_creds()
+        service_ticket = self.get_service_ticket(tgt, service_creds)
+
+        self._run_tgs(service_ticket,
+                      expected_error=(KDC_ERR_NOT_US, KDC_ERR_POLICY))
+
+    def test_renew_service_ticket(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds)
+
+        service_creds = self.get_service_creds()
+        service_ticket = self.get_service_ticket(tgt, service_creds)
+
+        service_ticket = self.modified_ticket(
+            service_ticket,
+            modify_fn=self._modify_renewable,
+            checksum_keys=self.get_krbtgt_checksum_key())
+
+        self._renew_tgt(service_ticket,
+                        expected_error=KDC_ERR_POLICY)
+
+    def test_validate_service_ticket(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds)
+
+        service_creds = self.get_service_creds()
+        service_ticket = self.get_service_ticket(tgt, service_creds)
+
+        service_ticket = self.modified_ticket(
+            service_ticket,
+            modify_fn=self._modify_invalid,
+            checksum_keys=self.get_krbtgt_checksum_key())
+
+        self._validate_tgt(service_ticket,
+                           expected_error=KDC_ERR_POLICY)
+
+    def test_s4u2self_service_ticket(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds)
+
+        service_creds = self.get_service_creds()
+        service_ticket = self.get_service_ticket(tgt, service_creds)
+
+        self._s4u2self(service_ticket, creds,
+                       expected_error=(KDC_ERR_NOT_US, KDC_ERR_POLICY))
+
     def test_user2user_service_ticket(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds)
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 2aa7fb2b370..8f8b0b18f18 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -381,6 +381,7 @@ 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_renew_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
@@ -442,6 +443,7 @@ 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_validate_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_nonexisting
 #
-- 
2.25.1


From e24898c41c572dc8ec1374e67a4e029207b21ee2 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 12:09:18 +1300
Subject: [PATCH 31/99] tests/krb5: Add TGS-REQ tests with FAST

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit ec823c2a83c639f1d7c422153a53d366750e5f2a)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 184 ++++++++++++++++++++++-
 selftest/knownfail_heimdal_kdc           |  13 ++
 selftest/knownfail_mit_kdc               |  17 +++
 3 files changed, 212 insertions(+), 2 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 52297c963e8..99a91528fa8 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -32,6 +32,7 @@ os.environ["PYTHONUNBUFFERED"] = "1"
 
 import samba.tests.krb5.kcrypto as kcrypto
 from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.raw_testcase import Krb5EncryptionKey
 from samba.tests.krb5.rfc4120_constants import (
     AES256_CTS_HMAC_SHA1_96,
     ARCFOUR_HMAC_MD5,
@@ -513,6 +514,11 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds)
         self._user2user(tgt, creds, expected_error=0)
 
+    def test_fast_req(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds)
+        self._fast(tgt, creds, expected_error=0)
+
     def test_tgs_req_invalid(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, invalid=True)
@@ -528,6 +534,12 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds, invalid=True)
         self._user2user(tgt, creds, expected_error=KRB_ERR_TKT_NYV)
 
+    def test_fast_req_invalid(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds, invalid=True)
+        self._fast(tgt, creds, expected_error=KRB_ERR_TKT_NYV,
+                   expected_sname=self.get_krbtgt_sname())
+
     def test_tgs_req_no_requester_sid(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, remove_requester_sid=True)
@@ -583,6 +595,12 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds, remove_pac=True)
         self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_no_pac(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds, remove_pac=True)
+        self._fast(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     # Test making a request with authdata and without a PAC.
     def test_tgs_authdata_no_pac(self):
         creds = self._get_creds()
@@ -613,6 +631,12 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
         self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_authdata_no_pac(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
+        self._fast(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     # Test changing the SID in the PAC to that of another account.
     def test_tgs_sid_mismatch_existing(self):
         creds = self._get_creds()
@@ -646,6 +670,14 @@ class KdcTgsTests(KDCBaseTest):
         self._user2user(tgt, creds,
                         expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_sid_mismatch_existing(self):
+        creds = self._get_creds()
+        existing_rid = self._get_existing_rid()
+        tgt = self._get_tgt(creds, new_rid=existing_rid)
+        self._fast(tgt, creds,
+                   expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     def test_requester_sid_mismatch_existing(self):
         creds = self._get_creds()
         existing_rid = self._get_existing_rid()
@@ -702,6 +734,14 @@ class KdcTgsTests(KDCBaseTest):
         self._user2user(tgt, creds,
                         expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_sid_mismatch_nonexisting(self):
+        creds = self._get_creds()
+        nonexistent_rid = self._get_non_existent_rid()
+        tgt = self._get_tgt(creds, new_rid=nonexistent_rid)
+        self._fast(tgt, creds,
+                   expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     def test_requester_sid_mismatch_nonexisting(self):
         creds = self._get_creds()
         nonexistent_rid = self._get_non_existent_rid()
@@ -799,6 +839,16 @@ class KdcTgsTests(KDCBaseTest):
         self._user2user(tgt, creds,
                         expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_rodc_sid_mismatch_existing(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        existing_rid = self._get_existing_rid(replication_allowed=True,
+                                              revealed_to_rodc=True)
+        tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid)
+        self._fast(tgt, creds,
+                   expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     def test_tgs_rodc_requester_sid_mismatch_existing(self):
         creds = self._get_creds(replication_allowed=True,
                                 revealed_to_rodc=True)
@@ -866,6 +916,15 @@ class KdcTgsTests(KDCBaseTest):
         self._user2user(tgt, creds,
                         expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_rodc_sid_mismatch_nonexisting(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        nonexistent_rid = self._get_non_existent_rid()
+        tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid)
+        self._fast(tgt, creds,
+                   expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     def test_tgs_rodc_requester_sid_mismatch_nonexisting(self):
         creds = self._get_creds(replication_allowed=True,
                                 revealed_to_rodc=True)
@@ -955,6 +1014,14 @@ class KdcTgsTests(KDCBaseTest):
         self._remove_rodc_partial_secrets()
         self._user2user(tgt, creds, expected_error=KDC_ERR_POLICY)
 
+    def test_fast_rodc_no_partial_secrets(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self._get_tgt(creds, from_rodc=True)
+        self._remove_rodc_partial_secrets()
+        self._fast(tgt, creds, expected_error=KDC_ERR_POLICY,
+                   expected_sname=self.get_krbtgt_sname())
+
     # Test with an RODC-issued ticket where the RODC account does not have an
     # msDS-KrbTgtLink.
     def test_tgs_rodc_no_krbtgt_link(self):
@@ -992,6 +1059,14 @@ class KdcTgsTests(KDCBaseTest):
         self._remove_rodc_krbtgt_link()
         self._user2user(tgt, creds, expected_error=KDC_ERR_POLICY)
 
+    def test_fast_rodc_no_krbtgt_link(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self._get_tgt(creds, from_rodc=True)
+        self._remove_rodc_krbtgt_link()
+        self._fast(tgt, creds, expected_error=KDC_ERR_POLICY,
+                   expected_sname=self.get_krbtgt_sname())
+
     # Test with an RODC-issued ticket where the client is not allowed to
     # replicate to the RODC.
     def test_tgs_rodc_not_allowed(self):
@@ -1019,6 +1094,12 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds, from_rodc=True)
         self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_rodc_not_allowed(self):
+        creds = self._get_creds(revealed_to_rodc=True)
+        tgt = self._get_tgt(creds, from_rodc=True)
+        self._fast(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     # Test with an RODC-issued ticket where the client is denied from
     # replicating to the RODC.
     def test_tgs_rodc_denied(self):
@@ -1051,6 +1132,13 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds, from_rodc=True)
         self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_rodc_denied(self):
+        creds = self._get_creds(replication_denied=True,
+                                revealed_to_rodc=True)
+        tgt = self._get_tgt(creds, from_rodc=True)
+        self._fast(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     # Test with an RODC-issued ticket where the client is both allowed and
     # denied replicating to the RODC.
     def test_tgs_rodc_allowed_denied(self):
@@ -1088,6 +1176,14 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._get_tgt(creds, from_rodc=True)
         self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_fast_rodc_allowed_denied(self):
+        creds = self._get_creds(replication_allowed=True,
+                                replication_denied=True,
+                                revealed_to_rodc=True)
+        tgt = self._get_tgt(creds, from_rodc=True)
+        self._fast(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED,
+                   expected_sname=self.get_krbtgt_sname())
+
     # Test user-to-user with incorrect service principal names.
     def test_user2user_matching_sname_host(self):
         creds = self._get_creds()
@@ -1295,6 +1391,17 @@ class KdcTgsTests(KDCBaseTest):
         self._user2user(service_ticket, creds,
                         expected_error=(KDC_ERR_MODIFIED, KDC_ERR_POLICY))
 
+    # Expected to fail against Windows, which does not produce a policy error.
+    def test_fast_service_ticket(self):
+        creds = self._get_creds()
+        tgt = self._get_tgt(creds)
+
+        service_creds = self.get_service_creds()
+        service_ticket = self.get_service_ticket(tgt, service_creds)
+
+        self._fast(service_ticket, creds,
+                   expected_error=KDC_ERR_POLICY)
+
     def test_pac_attrs_none(self):
         creds = self._get_creds()
         self.get_tgt(creds, pac_request=None,
@@ -1792,6 +1899,34 @@ class KdcTgsTests(KDCBaseTest):
         pac = self.get_ticket_pac(ticket)
         self.assertIsNotNone(pac)
 
+    def test_fast_pac_request_none(self):
+        creds = self._get_creds()
+        tgt = self.get_tgt(creds, pac_request=None)
+
+        ticket = self._fast(tgt, creds, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
+    def test_fast_pac_request_false(self):
+        creds = self._get_creds()
+        tgt = self.get_tgt(creds, pac_request=False)
+
+        ticket = self._fast(tgt, creds, expected_error=0,
+                            expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket, expect_pac=True)
+        self.assertIsNotNone(pac)
+
+    def test_fast_pac_request_true(self):
+        creds = self._get_creds()
+        tgt = self.get_tgt(creds, pac_request=True)
+
+        ticket = self._fast(tgt, creds, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
     def test_tgs_rodc_pac_request_none(self):
         creds = self._get_creds(replication_allowed=True,
                                 revealed_to_rodc=True)
@@ -2192,13 +2327,28 @@ class KdcTgsTests(KDCBaseTest):
                              srealm=srealm,
                              expect_pac=expect_pac)
 
+    def _fast(self, armor_tgt, armor_tgt_creds, expected_error,
+              expected_sname=None, expect_pac=True):
+        user_creds = self._get_mach_creds()
+        user_tgt = self.get_tgt(user_creds)
+
+        target_creds = self.get_service_creds()
+
+        return self._tgs_req(user_tgt, expected_error, target_creds,
+                             armor_tgt=armor_tgt,
+                             expected_sname=expected_sname,
+                             expect_pac=expect_pac)
+
     def _tgs_req(self, tgt, expected_error, target_creds,
+                 armor_tgt=None,
                  kdc_options='0',
                  expected_cname=None,
+                 expected_sname=None,
                  additional_ticket=None,
                  generate_padata_fn=None,
                  sname=None,
                  srealm=None,
+                 use_fast=False,
                  expect_claims=True,
                  expect_pac=True,
                  expect_pac_attrs=None,
@@ -2214,7 +2364,8 @@ class KdcTgsTests(KDCBaseTest):
 
         if sname is False:
             sname = None
-            expected_sname = self.get_krbtgt_sname()
+            if expected_sname is None:
+                expected_sname = self.get_krbtgt_sname()
         else:
             if sname is None:
                 target_name = target_creds.get_username()
@@ -2229,7 +2380,8 @@ class KdcTgsTests(KDCBaseTest):
                         name_type=NT_PRINCIPAL,
                         names=['host', target_name])
 
-            expected_sname = sname
+            if expected_sname is None:
+                expected_sname = sname
 
         if additional_ticket is not None:
             additional_tickets = [additional_ticket.ticket]
@@ -2241,6 +2393,28 @@ class KdcTgsTests(KDCBaseTest):
 
         subkey = self.RandomKey(tgt.session_key.etype)
 
+        if armor_tgt is not None:
+            armor_subkey = self.RandomKey(subkey.etype)
+            explicit_armor_key = self.generate_armor_key(armor_subkey,
+                                                         armor_tgt.session_key)
+            armor_key = kcrypto.cf2(explicit_armor_key.key,
+                                    subkey.key,
+                                    b'explicitarmor',
+                                    b'tgsarmor')
+            armor_key = Krb5EncryptionKey(armor_key, None)
+
+            generate_fast_fn = self.generate_simple_fast
+            generate_fast_armor_fn = self.generate_ap_req
+
+            pac_options = '1'  # claims support
+        else:
+            armor_subkey = None
+            armor_key = None
+            generate_fast_fn = None
+            generate_fast_armor_fn = None
+
+            pac_options = None
+
         etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
 
         if expected_error:
@@ -2260,12 +2434,18 @@ class KdcTgsTests(KDCBaseTest):
             expected_sname=expected_sname,
             ticket_decryption_key=decryption_key,
             generate_padata_fn=generate_padata_fn,
+            generate_fast_fn=generate_fast_fn,
+            generate_fast_armor_fn=generate_fast_armor_fn,
             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,
             expected_status=expected_status,
             tgt=tgt,
+            armor_key=armor_key,
+            armor_tgt=armor_tgt,
+            armor_subkey=armor_subkey,
+            pac_options=pac_options,
             authenticator_subkey=subkey,
             kdc_options=kdc_options,
             expect_edata=expect_edata,
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index cfbe698fb15..42b70e97f60 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -112,6 +112,19 @@
 #
 # KDC TGS tests
 #
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_req_invalid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_allowed_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_no_krbtgt_link
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_no_partial_secrets
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_not_allowed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 8f8b0b18f18..1723481c931 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -368,6 +368,23 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 #
 # KDC TGT tests
 #
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_req
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_req_invalid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_allowed_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_no_krbtgt_link
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_no_partial_secrets
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_not_allowed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
-- 
2.25.1


From 42f09fdbdbdc1c2a6fc6c29e8df9c54c345c8fbf Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 12:37:08 +1300
Subject: [PATCH 32/99] tests/krb5: Align PAC buffer checking to more closely
 match Windows with PacRequestorEnforcement=2

We set EXPECT_EXTRA_PAC_BUFFERS to 0 for the moment. This signifies that
these checks are currently not enforced, which avoids a lot of test
failures.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit ebc9137cee94dee9dcf0e47d5bc0dc83de7aaaa1)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 121 ++++++++++++++++-------
 python/samba/tests/krb5/raw_testcase.py  |  39 ++++++--
 selftest/knownfail_heimdal_kdc           |   9 ++
 selftest/knownfail_mit_kdc               |   6 ++
 source4/selftest/tests.py                |  58 +++++++----
 5 files changed, 168 insertions(+), 65 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 99a91528fa8..f14439a4ab5 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -497,12 +497,18 @@ class KdcTgsTests(KDCBaseTest):
     def test_renew_req(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, renewable=True)
-        self._renew_tgt(tgt, expected_error=0)
+        self._renew_tgt(tgt, expected_error=0,
+                        expect_pac_attrs=True,
+                        expect_pac_attrs_pac_request=True,
+                        expect_requester_sid=True)
 
     def test_validate_req(self):
         creds = self._get_creds()
         tgt = self._get_tgt(creds, invalid=True)
-        self._validate_tgt(tgt, expected_error=0)
+        self._validate_tgt(tgt, expected_error=0,
+                           expect_pac_attrs=True,
+                           expect_pac_attrs_pac_request=True,
+                           expect_requester_sid=True)
 
     def test_s4u2self_req(self):
         creds = self._get_creds()
@@ -774,13 +780,17 @@ class KdcTgsTests(KDCBaseTest):
         creds = self._get_creds(replication_allowed=True,
                                 revealed_to_rodc=True)
         tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
-        self._renew_tgt(tgt, expected_error=0)
+        self._renew_tgt(tgt, expected_error=0,
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_validate_rodc_revealed(self):
         creds = self._get_creds(replication_allowed=True,
                                 revealed_to_rodc=True)
         tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
-        self._validate_tgt(tgt, expected_error=0)
+        self._validate_tgt(tgt, expected_error=0,
+                           expect_pac_attrs=False,
+                           expect_requester_sid=True)
 
     def test_s4u2self_rodc_revealed(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1434,7 +1444,8 @@ class KdcTgsTests(KDCBaseTest):
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
                         expect_pac_attrs=True,
-                        expect_pac_attrs_pac_request=None)
+                        expect_pac_attrs_pac_request=None,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_renew_false(self):
         creds = self._get_creds()
@@ -1447,7 +1458,8 @@ class KdcTgsTests(KDCBaseTest):
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
                         expect_pac_attrs=True,
-                        expect_pac_attrs_pac_request=False)
+                        expect_pac_attrs_pac_request=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_renew_true(self):
         creds = self._get_creds()
@@ -1460,7 +1472,8 @@ class KdcTgsTests(KDCBaseTest):
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
                         expect_pac_attrs=True,
-                        expect_pac_attrs_pac_request=True)
+                        expect_pac_attrs_pac_request=True,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_rodc_renew_none(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1473,8 +1486,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=True,
-                        expect_pac_attrs_pac_request=None)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_rodc_renew_false(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1487,8 +1500,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=True,
-                        expect_pac_attrs_pac_request=False)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_rodc_renew_true(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1501,8 +1514,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=True,
-                        expect_pac_attrs_pac_request=True)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_missing_renew_none(self):
         creds = self._get_creds()
@@ -1515,7 +1528,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=False)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_missing_renew_false(self):
         creds = self._get_creds()
@@ -1528,7 +1542,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=False)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_missing_renew_true(self):
         creds = self._get_creds()
@@ -1541,7 +1556,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=False)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_missing_rodc_renew_none(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1555,7 +1571,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=False)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_missing_rodc_renew_false(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1569,7 +1586,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=False)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_pac_attrs_missing_rodc_renew_true(self):
         creds = self._get_creds(replication_allowed=True,
@@ -1583,7 +1601,8 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=0,
                         expect_pac=True,
-                        expect_pac_attrs=False)
+                        expect_pac_attrs=False,
+                        expect_requester_sid=True)
 
     def test_tgs_pac_attrs_none(self):
         creds = self._get_creds()
@@ -1593,8 +1612,7 @@ class KdcTgsTests(KDCBaseTest):
                            expect_pac_attrs_pac_request=None)
 
         self._run_tgs(tgt, expected_error=0, expect_pac=True,
-                      expect_pac_attrs=True,
-                      expect_pac_attrs_pac_request=None)
+                      expect_pac_attrs=False)
 
     def test_tgs_pac_attrs_false(self):
         creds = self._get_creds()
@@ -1603,7 +1621,8 @@ class KdcTgsTests(KDCBaseTest):
                            expect_pac_attrs=True,
                            expect_pac_attrs_pac_request=False)
 
-        self._run_tgs(tgt, expected_error=0, expect_pac=False)
+        self._run_tgs(tgt, expected_error=0, expect_pac=False,
+                      expect_pac_attrs=False)
 
     def test_tgs_pac_attrs_true(self):
         creds = self._get_creds()
@@ -1613,8 +1632,7 @@ class KdcTgsTests(KDCBaseTest):
                            expect_pac_attrs_pac_request=True)
 
         self._run_tgs(tgt, expected_error=0, expect_pac=True,
-                      expect_pac_attrs=True,
-                      expect_pac_attrs_pac_request=True)
+                      expect_pac_attrs=False)
 
     def test_as_requester_sid(self):
         creds = self._get_creds()
@@ -1639,8 +1657,7 @@ class KdcTgsTests(KDCBaseTest):
                            expect_requester_sid=True)
 
         self._run_tgs(tgt, expected_error=0, expect_pac=True,
-                      expected_sid=sid,
-                      expect_requester_sid=True)
+                      expect_requester_sid=False)
 
     def test_tgs_requester_sid_renew(self):
         creds = self._get_creds()
@@ -1655,6 +1672,8 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._modify_tgt(tgt, renewable=True)
 
         self._renew_tgt(tgt, expected_error=0, expect_pac=True,
+                        expect_pac_attrs=True,
+                        expect_pac_attrs_pac_request=None,
                         expected_sid=sid,
                         expect_requester_sid=True)
 
@@ -1672,6 +1691,7 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True)
 
         self._renew_tgt(tgt, expected_error=0, expect_pac=True,
+                        expect_pac_attrs=False,
                         expected_sid=sid,
                         expect_requester_sid=True)
 
@@ -1738,7 +1758,10 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self.get_tgt(creds, pac_request=None)
         tgt = self._modify_tgt(tgt, renewable=True)
 
-        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None)
+        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None,
+                              expect_pac_attrs=True,
+                              expect_pac_attrs_pac_request=None,
+                              expect_requester_sid=True)
 
         ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
 
@@ -1750,7 +1773,10 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
         tgt = self._modify_tgt(tgt, renewable=True)
 
-        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None)
+        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None,
+                              expect_pac_attrs=True,
+                              expect_pac_attrs_pac_request=False,
+                              expect_requester_sid=True)
 
         ticket = self._run_tgs(tgt, expected_error=0, expect_pac=False)
 
@@ -1762,7 +1788,10 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self.get_tgt(creds, pac_request=True)
         tgt = self._modify_tgt(tgt, renewable=True)
 
-        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None)
+        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None,
+                              expect_pac_attrs=True,
+                              expect_pac_attrs_pac_request=True,
+                              expect_requester_sid=True)
 
         ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
 
@@ -1774,7 +1803,10 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self.get_tgt(creds, pac_request=None)
         tgt = self._modify_tgt(tgt, invalid=True)
 
-        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None)
+        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None,
+                                 expect_pac_attrs=True,
+                                 expect_pac_attrs_pac_request=None,
+                                 expect_requester_sid=True)
 
         ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
 
@@ -1786,7 +1818,10 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
         tgt = self._modify_tgt(tgt, invalid=True)
 
-        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None)
+        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None,
+                                 expect_pac_attrs=True,
+                                 expect_pac_attrs_pac_request=False,
+                                 expect_requester_sid=True)
 
         ticket = self._run_tgs(tgt, expected_error=0, expect_pac=False)
 
@@ -1798,7 +1833,10 @@ class KdcTgsTests(KDCBaseTest):
         tgt = self.get_tgt(creds, pac_request=True)
         tgt = self._modify_tgt(tgt, invalid=True)
 
-        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None)
+        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None,
+                                 expect_pac_attrs=True,
+                                 expect_pac_attrs_pac_request=True,
+                                 expect_requester_sid=True)
 
         ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
 
@@ -1946,7 +1984,7 @@ class KdcTgsTests(KDCBaseTest):
 
         ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
 
-        pac = self.get_ticket_pac(ticket, expect_pac=False)
+        pac = self.get_ticket_pac(ticket)
         self.assertIsNotNone(pac)
 
     def test_tgs_rodc_pac_request_true(self):
@@ -2279,12 +2317,21 @@ class KdcTgsTests(KDCBaseTest):
             expect_requester_sid=expect_requester_sid,
             expected_sid=expected_sid)
 
-    def _validate_tgt(self, tgt, expected_error, expect_pac=True):
+    def _validate_tgt(self, tgt, expected_error, expect_pac=True,
+                      expect_pac_attrs=None,
+                      expect_pac_attrs_pac_request=None,
+                      expect_requester_sid=None,
+                      expected_sid=None):
         krbtgt_creds = self.get_krbtgt_creds()
         kdc_options = str(krb5_asn1.KDCOptions('validate'))
-        return self._tgs_req(tgt, expected_error, krbtgt_creds,
-                             kdc_options=kdc_options,
-                             expect_pac=expect_pac)
+        return self._tgs_req(
+            tgt, expected_error, krbtgt_creds,
+            kdc_options=kdc_options,
+            expect_pac=expect_pac,
+            expect_pac_attrs=expect_pac_attrs,
+            expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
+            expect_requester_sid=expect_requester_sid,
+            expected_sid=expected_sid)
 
     def _s4u2self(self, tgt, tgt_creds, expected_error, expect_pac=True,
                   expect_edata=False, expected_status=None):
diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index da3f69c79c6..14e655313fc 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -602,6 +602,13 @@ class RawKerberosTest(TestCaseInTempDir):
             expect_pac = '1'
         cls.expect_pac = bool(int(expect_pac))
 
+        expect_extra_pac_buffers = samba.tests.env_get_var_value(
+            'EXPECT_EXTRA_PAC_BUFFERS',
+            allow_missing=True)
+        if expect_extra_pac_buffers is None:
+            expect_extra_pac_buffers = '1'
+        cls.expect_extra_pac_buffers = bool(int(expect_extra_pac_buffers))
+
     def setUp(self):
         super().setUp()
         self.do_asn1_print = False
@@ -2624,17 +2631,34 @@ class RawKerberosTest(TestCaseInTempDir):
         if not self.tkt_sig_support:
             require_strict.add(krb5pac.PAC_TYPE_TICKET_CHECKSUM)
 
+        expect_extra_pac_buffers = rep_msg_type == KRB_AS_REP
+
         expect_pac_attrs = kdc_exchange_dict['expect_pac_attrs']
+
+        if expect_pac_attrs:
+            expect_pac_attrs_pac_request = kdc_exchange_dict[
+                'expect_pac_attrs_pac_request']
+        else:
+            expect_pac_attrs_pac_request = kdc_exchange_dict[
+                'pac_request']
+
+        if expect_pac_attrs is None:
+            if self.expect_extra_pac_buffers:
+                expect_pac_attrs = expect_extra_pac_buffers
+            else:
+                require_strict.add(krb5pac.PAC_TYPE_ATTRIBUTES_INFO)
         if expect_pac_attrs:
             expected_types.append(krb5pac.PAC_TYPE_ATTRIBUTES_INFO)
-        elif expect_pac_attrs is None:
-            require_strict.add(krb5pac.PAC_TYPE_ATTRIBUTES_INFO)
 
         expect_requester_sid = kdc_exchange_dict['expect_requester_sid']
+
+        if expect_requester_sid is None:
+            if self.expect_extra_pac_buffers:
+                expect_requester_sid = expect_extra_pac_buffers
+            else:
+                require_strict.add(krb5pac.PAC_TYPE_REQUESTER_SID)
         if expect_requester_sid:
             expected_types.append(krb5pac.PAC_TYPE_REQUESTER_SID)
-        elif expect_requester_sid is None:
-            require_strict.add(krb5pac.PAC_TYPE_REQUESTER_SID)
 
         buffer_types = [pac_buffer.type
                         for pac_buffer in pac.buffers]
@@ -2722,9 +2746,6 @@ class RawKerberosTest(TestCaseInTempDir):
                 requested_pac = bool(flags & 1)
                 given_pac = bool(flags & 2)
 
-                expect_pac_attrs_pac_request = kdc_exchange_dict[
-                    'expect_pac_attrs_pac_request']
-
                 self.assertEqual(expect_pac_attrs_pac_request is True,
                                  requested_pac)
                 self.assertEqual(expect_pac_attrs_pac_request is None,
@@ -2734,8 +2755,8 @@ class RawKerberosTest(TestCaseInTempDir):
                       and expect_requester_sid):
                 requester_sid = pac_buffer.info.sid
 
-                self.assertIsNotNone(expected_sid)
-                self.assertEqual(expected_sid, str(requester_sid))
+                if expected_sid is not None:
+                    self.assertEqual(expected_sid, str(requester_sid))
 
     def generic_check_kdc_error(self,
                                 kdc_exchange_dict,
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 42b70e97f60..475abc03182 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -127,11 +127,15 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing
@@ -147,10 +151,14 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid(?!_)
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_false
@@ -170,6 +178,7 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 1723481c931..1e63bb33d03 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -389,6 +389,9 @@ 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_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_req
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_krbtgt_link
@@ -451,6 +454,9 @@ 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_user2user_wrong_srealm
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_req
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_krbtgt_link
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index ff523edd26b..7234767baa5 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -905,12 +905,14 @@ for env in ['fileserver_smb1', 'nt4_member', 'clusteredmember', 'ktest', 'nt4_dc
 have_fast_support = int('SAMBA_USES_MITKDC' in config_hash)
 tkt_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash)
 expect_pac = int('SAMBA4_USES_HEIMDAL' in config_hash)
+extra_pac_buffers = 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,
                                 'TKT_SIG_SUPPORT': tkt_sig_support,
-                                'EXPECT_PAC': expect_pac})
+                                'EXPECT_PAC': expect_pac,
+                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
 planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests",
                        environ={'ADMIN_USERNAME':'$USERNAME',
                                 'ADMIN_PASSWORD':'$PASSWORD',
@@ -918,21 +920,24 @@ planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests",
                                 'STRICT_CHECKING':'0',
                                 'FAST_SUPPORT': have_fast_support,
                                 'TKT_SIG_SUPPORT': tkt_sig_support,
-                                'EXPECT_PAC': expect_pac})
+                                'EXPECT_PAC': expect_pac,
+                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
 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,
-                                'EXPECT_PAC': expect_pac})
+                                'EXPECT_PAC': expect_pac,
+                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
 
 planoldpythontestsuite("ad_dc_default", "samba.tests.dsdb_dns")
 
 planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests",
                        environ={'FAST_SUPPORT': have_fast_support,
                                 'TKT_SIG_SUPPORT': tkt_sig_support,
-                                'EXPECT_PAC': expect_pac})
+                                'EXPECT_PAC': expect_pac,
+                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
 
 planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ccache",
                        environ={
@@ -941,7 +946,8 @@ planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ccache",
                            'STRICT_CHECKING': '0',
                            'FAST_SUPPORT': have_fast_support,
                            'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac
+                           'EXPECT_PAC': expect_pac,
+                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                        })
 planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap",
                        environ={
@@ -950,7 +956,8 @@ planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap",
                            'STRICT_CHECKING': '0',
                            'FAST_SUPPORT': have_fast_support,
                            'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac
+                           'EXPECT_PAC': expect_pac,
+                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                        })
 for env in ['ad_dc_default', 'ad_member']:
     planoldpythontestsuite(env, "samba.tests.krb5.test_rpc",
@@ -960,7 +967,8 @@ for env in ['ad_dc_default', 'ad_member']:
                                'STRICT_CHECKING': '0',
                                'FAST_SUPPORT': have_fast_support,
                                'TKT_SIG_SUPPORT': tkt_sig_support,
-                               'EXPECT_PAC': expect_pac
+                               'EXPECT_PAC': expect_pac,
+                               'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                            })
 planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb",
                        environ={
@@ -969,7 +977,8 @@ planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb",
                            'STRICT_CHECKING': '0',
                            'FAST_SUPPORT': have_fast_support,
                            'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac
+                           'EXPECT_PAC': expect_pac,
+                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                        })
 planoldpythontestsuite("ad_member_idmap_nss:local",
                        "samba.tests.krb5.test_min_domain_uid",
@@ -992,7 +1001,8 @@ planoldpythontestsuite("ad_member_idmap_nss:local",
                            'STRICT_CHECKING': '0',
                            'FAST_SUPPORT': have_fast_support,
                            'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac
+                           'EXPECT_PAC': expect_pac,
+                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                        })
 
 for env in ["ad_dc", smbv1_disabled_testenv]:
@@ -1587,7 +1597,8 @@ for env in ["fl2008r2dc", "fl2003dc"]:
                                'STRICT_CHECKING': '0',
                                'FAST_SUPPORT': have_fast_support,
                                'TKT_SIG_SUPPORT': tkt_sig_support,
-                               'EXPECT_PAC': expect_pac
+                               'EXPECT_PAC': expect_pac,
+                               'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                            })
 
 planoldpythontestsuite('fl2008r2dc', 'samba.tests.krb5.salt_tests',
@@ -1597,7 +1608,8 @@ planoldpythontestsuite('fl2008r2dc', 'samba.tests.krb5.salt_tests',
                            'STRICT_CHECKING': '0',
                            'FAST_SUPPORT': have_fast_support,
                            'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac
+                           'EXPECT_PAC': expect_pac,
+                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                        })
 
 for env in ["rodc", "promoted_dc", "fl2000dc", "fl2008r2dc"]:
@@ -1620,7 +1632,8 @@ planpythontestsuite("ad_dc", "samba.tests.krb5.as_canonicalization_tests",
                            'ADMIN_PASSWORD': '$PASSWORD',
                            'FAST_SUPPORT': have_fast_support,
                            'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac
+                           'EXPECT_PAC': expect_pac,
+                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                        })
 planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests",
                     environ={
@@ -1629,12 +1642,14 @@ planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests",
                         'STRICT_CHECKING': '0',
                         'FAST_SUPPORT': have_fast_support,
                         'TKT_SIG_SUPPORT': tkt_sig_support,
-                        'EXPECT_PAC': expect_pac
+                        'EXPECT_PAC': expect_pac,
+                        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                     })
 planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests",
                     environ={'FAST_SUPPORT': have_fast_support,
                              'TKT_SIG_SUPPORT': tkt_sig_support,
-                             'EXPECT_PAC': expect_pac})
+                             'EXPECT_PAC': expect_pac,
+                             'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
 planpythontestsuite(
     "ad_dc",
     "samba.tests.krb5.kdc_tgs_tests",
@@ -1644,7 +1659,8 @@ planpythontestsuite(
         'STRICT_CHECKING': '0',
         'FAST_SUPPORT': have_fast_support,
         'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac
+        'EXPECT_PAC': expect_pac,
+        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
     })
 planpythontestsuite(
     "ad_dc",
@@ -1655,7 +1671,8 @@ planpythontestsuite(
         'STRICT_CHECKING': '0',
         'FAST_SUPPORT': have_fast_support,
         'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac
+        'EXPECT_PAC': expect_pac,
+        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
     })
 planpythontestsuite(
     "ad_dc",
@@ -1666,7 +1683,8 @@ planpythontestsuite(
         'STRICT_CHECKING': '0',
         'FAST_SUPPORT': have_fast_support,
         'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac
+        'EXPECT_PAC': expect_pac,
+        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
     })
 planpythontestsuite(
     "ad_dc",
@@ -1677,7 +1695,8 @@ planpythontestsuite(
         'STRICT_CHECKING': '0',
         'FAST_SUPPORT': have_fast_support,
         'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac
+        'EXPECT_PAC': expect_pac,
+        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
     })
 planpythontestsuite(
     "ad_dc",
@@ -1688,7 +1707,8 @@ planpythontestsuite(
         'STRICT_CHECKING': '0',
         'FAST_SUPPORT': have_fast_support,
         'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac
+        'EXPECT_PAC': expect_pac,
+        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
     })
 
 for env in [
-- 
2.25.1


From 17e724b5bbfcaa96f2d4f4d9be790a0f7effe877 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 13:10:52 +1300
Subject: [PATCH 33/99] tests/krb5: Add tests for validation with requester SID
 PAC buffer

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit ca80c47406e0f2b6fac2c55229306e21ccef9745)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 67 ++++++++++++++++++++++++
 selftest/knownfail_heimdal_kdc           |  3 ++
 selftest/knownfail_mit_kdc               |  4 ++
 3 files changed, 74 insertions(+)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index f14439a4ab5..50079a1710c 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -1726,6 +1726,73 @@ class KdcTgsTests(KDCBaseTest):
 
         self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
 
+    def test_tgs_requester_sid_validate(self):
+        creds = self._get_creds()
+
+        samdb = self.get_samdb()
+        sid = self.get_objectSid(samdb, creds.get_dn())
+
+        tgt = self.get_tgt(creds, pac_request=None,
+                           expect_pac=True,
+                           expected_sid=sid,
+                           expect_requester_sid=True)
+        tgt = self._modify_tgt(tgt, invalid=True)
+
+        self._validate_tgt(tgt, expected_error=0, expect_pac=True,
+                           expect_pac_attrs=True,
+                           expect_pac_attrs_pac_request=None,
+                           expected_sid=sid,
+                           expect_requester_sid=True)
+
+    def test_tgs_requester_sid_rodc_validate(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+
+        samdb = self.get_samdb()
+        sid = self.get_objectSid(samdb, creds.get_dn())
+
+        tgt = self.get_tgt(creds, pac_request=None,
+                           expect_pac=True,
+                           expected_sid=sid,
+                           expect_requester_sid=True)
+        tgt = self._modify_tgt(tgt, from_rodc=True, invalid=True)
+
+        self._validate_tgt(tgt, expected_error=0, expect_pac=True,
+                           expect_pac_attrs=False,
+                           expected_sid=sid,
+                           expect_requester_sid=True)
+
+    def test_tgs_requester_sid_missing_validate(self):
+        creds = self._get_creds()
+
+        samdb = self.get_samdb()
+        sid = self.get_objectSid(samdb, creds.get_dn())
+
+        tgt = self.get_tgt(creds, pac_request=None,
+                           expect_pac=True,
+                           expected_sid=sid,
+                           expect_requester_sid=True)
+        tgt = self._modify_tgt(tgt, invalid=True,
+                               remove_requester_sid=True)
+
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+    def test_tgs_requester_sid_missing_rodc_validate(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+
+        samdb = self.get_samdb()
+        sid = self.get_objectSid(samdb, creds.get_dn())
+
+        tgt = self.get_tgt(creds, pac_request=None,
+                           expect_pac=True,
+                           expected_sid=sid,
+                           expect_requester_sid=True)
+        tgt = self._modify_tgt(tgt, from_rodc=True, invalid=True,
+                               remove_requester_sid=True)
+
+        self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
     def test_tgs_pac_request_none(self):
         creds = self._get_creds()
         tgt = self.get_tgt(creds, pac_request=None)
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 475abc03182..c67cc302283 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -158,7 +158,10 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid(?!_)
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_validate
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_false
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 1e63bb33d03..76253fc7b4b 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -512,8 +512,12 @@ 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_tgs_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_validate
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_sid_mismatch_existing
-- 
2.25.1


From 79ba192a73f601a86a59ef16aaf47c649790a980 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 15:32:32 +1300
Subject: [PATCH 34/99] tests/krb5: Add comments for tests that fail against
 Windows

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 749349efab9b401d33a4fc286473a924364a41c9)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 50079a1710c..ecc38538e61 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -792,6 +792,8 @@ class KdcTgsTests(KDCBaseTest):
                            expect_pac_attrs=False,
                            expect_requester_sid=True)
 
+    # This test fails on Windows, which gives KDC_ERR_C_PRINCIPAL_UNKNOWN when
+    # attempting to use S4U2Self with a TGT from an RODC.
     def test_s4u2self_rodc_revealed(self):
         creds = self._get_creds(replication_allowed=True,
                                 revealed_to_rodc=True)
@@ -2370,6 +2372,8 @@ class KdcTgsTests(KDCBaseTest):
             expect_requester_sid=expect_requester_sid,
             expected_sid=expected_sid)
 
+    # These tests fail against Windows, which does not implement ticket
+    # renewal.
     def _renew_tgt(self, tgt, expected_error, expect_pac=True,
                    expect_pac_attrs=None, expect_pac_attrs_pac_request=None,
                    expect_requester_sid=None, expected_sid=None):
@@ -2384,6 +2388,8 @@ class KdcTgsTests(KDCBaseTest):
             expect_requester_sid=expect_requester_sid,
             expected_sid=expected_sid)
 
+    # These tests fail against Windows, which does not implement ticket
+    # validation.
     def _validate_tgt(self, tgt, expected_error, expect_pac=True,
                       expect_pac_attrs=None,
                       expect_pac_attrs_pac_request=None,
-- 
2.25.1


From 78a82907caa55f9e6118fc2f7aa01509257fa166 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 18 Nov 2021 13:14:51 +1300
Subject: [PATCH 35/99] heimdal:kdc: Fix error message for user-to-user

We were checking the wrong variable to see whether a PAC was found or not.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 11fb9476ad3c09415d12b3cdf7934c293cbefcb2)
---
 source4/heimdal/kdc/krb5tgs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index fb2ef8230c9..cde68b41714 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -1629,7 +1629,7 @@ server_lookup:
 		ret = KRB5KDC_ERR_BADOPTION;
 		kdc_log(context, config, 0,
 			"Ticket not signed with PAC; user-to-user failed (%s).",
-			mspac ? "Ticket unsigned" : "No PAC");
+			user2user_pac ? "Ticket unsigned" : "No PAC");
 		goto out;
 	    }
 
-- 
2.25.1


From 9b5612a88c0a56b0a08595d21c87d1dff00e495a Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 18 Nov 2021 16:22:34 +1300
Subject: [PATCH 36/99] s4:torture: Fix typo

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 9cfb88ba04818b5e9cec3c96422e8e4a3080d490)
---
 source4/torture/krb5/kdc-canon-heimdal.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/krb5/kdc-canon-heimdal.c b/source4/torture/krb5/kdc-canon-heimdal.c
index e9466f2d9d7..38b3f1e7a62 100644
--- a/source4/torture/krb5/kdc-canon-heimdal.c
+++ b/source4/torture/krb5/kdc-canon-heimdal.c
@@ -262,7 +262,7 @@ static bool torture_krb5_pre_send_as_req_test(struct torture_krb5_context *test_
 						 KRB5_NT_PRINCIPAL,
 						 "krb5 libs unexpectedly "
 						 "did not set principal "
-						 "as NT_SRV_HST!");
+						 "as NT_PRINCIPAL!");
 		} else {
 			torture_assert_int_equal(test_context->tctx,
 						 test_context->as_req.req_body.cname->name_type,
-- 
2.25.1


From 37f9d30cbdaeb082382304d5cd6442ffcdca331e Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 20:41:34 +1300
Subject: [PATCH 37/99] heimdal:kdc: Adjust no-PAC error code to match Windows

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit f7a2fef8f49a86f63c3dc2f6a2d7d979fb53238a)
---
 selftest/knownfail_heimdal_kdc | 19 -------------------
 source4/heimdal/kdc/krb5tgs.c  |  2 +-
 2 files changed, 1 insertion(+), 20 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index c67cc302283..cf196a3260a 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -71,21 +71,15 @@
 # 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_client_pac(?!_no_auth_data_required)
-^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_no_auth_data_required
 ^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_no_service_pac
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_service_pac_no_auth_data_required
 ^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_forwardable
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_no_pac
 ^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_constrained_delegation_no_auth_data_required
@@ -130,11 +124,6 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
@@ -142,15 +131,11 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
@@ -171,16 +156,12 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index cde68b41714..6c5c51aa448 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -78,7 +78,7 @@ check_PAC(krb5_context context,
 	return ret;
 
     if (pac == NULL)
-	return KRB5KDC_ERR_BADOPTION;
+	return KRB5KDC_ERR_TGT_REVOKED;
 
     /* Verify the server signature. */
     ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
-- 
2.25.1


From 1bd26a254f2b7861852142e256c6d3bf7f718857 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 20:41:45 +1300
Subject: [PATCH 38/99] kdc: Adjust SID mismatch error code to match Windows

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit d5d22bf84a71492342287e54b555c9f024e7e71c)
---
 selftest/knownfail_heimdal_kdc | 35 ----------------------------------
 selftest/knownfail_mit_kdc     |  8 --------
 source4/kdc/pac-glue.c         |  6 +-----
 3 files changed, 1 insertion(+), 48 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index cf196a3260a..fc2a3554f0d 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -97,13 +97,6 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed
 #
-# Alias tests
-#
-^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_delete
-^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_rename
-^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_delete
-^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_rename
-#
 # KDC TGS tests
 #
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_authdata_no_pac
@@ -119,23 +112,11 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_revealed
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
@@ -147,23 +128,7 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_nonexisting
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 76253fc7b4b..806aaa707d7 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -385,8 +385,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_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_pac_request_none
@@ -402,8 +400,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_renew_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_service_ticket
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req(?!_invalid)
@@ -431,8 +427,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_tgs_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_sname
@@ -467,8 +461,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_validate_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_service_ticket
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_nonexisting
 #
 # PAC attributes tests
 #
diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c
index e0e483662c0..2a96a683cd9 100644
--- a/source4/kdc/pac-glue.c
+++ b/source4/kdc/pac-glue.c
@@ -1237,11 +1237,7 @@ krb5_error_code samba_kdc_validate_pac_blob(
 			"PAC[%s] != CLI[%s]\n",
 			dom_sid_str_buf(&pac_sid, &buf1),
 			dom_sid_str_buf(client_sid, &buf2));
-#if defined(KRB5KDC_ERR_CLIENT_NAME_MISMATCH) /* MIT */
-			code = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
-#else /* Heimdal (where this is an enum) */
-			code = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
-#endif
+			code = KRB5KDC_ERR_TGT_REVOKED;
 		goto out;
 	}
 
-- 
2.25.1


From 99a11ec7e78aa8bc477de18253f068f3a0c84c19 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 25 Nov 2021 10:05:17 +1300
Subject: [PATCH 39/99] tests/krb5: Add test for S4U2Self with wrong sname

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit bac5f75059450898937be891e863826e1350b62c)
---
 python/samba/tests/krb5/s4u_tests.py | 32 +++++++++++++++++++++++++++-
 selftest/knownfail_heimdal_kdc       |  1 +
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py
index 5f37525f393..2953766ef21 100755
--- a/python/samba/tests/krb5/s4u_tests.py
+++ b/python/samba/tests/krb5/s4u_tests.py
@@ -36,6 +36,7 @@ from samba.tests.krb5.raw_testcase import (
 from samba.tests.krb5.rfc4120_constants import (
     AES256_CTS_HMAC_SHA1_96,
     ARCFOUR_HMAC_MD5,
+    KDC_ERR_BADMATCH,
     KDC_ERR_BADOPTION,
     KDC_ERR_BAD_INTEGRITY,
     KDC_ERR_GENERIC,
@@ -243,7 +244,9 @@ class S4UKerberosTests(KDCBaseTest):
         client_dn = client_creds.get_dn()
         sid = self.get_objectSid(samdb, client_dn)
 
-        service_name = service_creds.get_username()[:-1]
+        service_name = kdc_dict.pop('service_name', None)
+        if service_name is None:
+            service_name = service_creds.get_username()[:-1]
         service_sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
                                                   names=['host', service_name])
 
@@ -474,6 +477,33 @@ class S4UKerberosTests(KDCBaseTest):
                 'expected_flags': 'forwardable'
             })
 
+    # Do an S4U2Self with the sname in the request different to that of the
+    # service. We expect an error.
+    def test_s4u2self_wrong_sname(self):
+        other_creds = self.get_cached_creds(
+            account_type=self.AccountType.COMPUTER,
+            opts={
+                'trusted_to_auth_for_delegation': True,
+                'id': 0
+            })
+        other_sname = other_creds.get_username()[:-1]
+
+        self._run_s4u2self_test(
+            {
+                'expected_error_mode': KDC_ERR_BADMATCH,
+                'expect_edata': False,
+                'client_opts': {
+                    'not_delegated': False
+                },
+                'service_opts': {
+                    'trusted_to_auth_for_delegation': True
+                },
+                'service_name': other_sname,
+                'kdc_options': 'forwardable',
+                'modify_service_tgt_fn': functools.partial(
+                    self.set_ticket_forwardable, flag=True)
+            })
+
     def _run_delegation_test(self, kdc_dict):
         client_opts = kdc_dict.pop('client_opts', None)
         client_creds = self.get_cached_creds(
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index fc2a3554f0d..fd05719cc4c 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -81,6 +81,7 @@
 ^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_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_wrong_sname
 #
 ^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
-- 
2.25.1


From daef3c8a3607575e077c2eff55a06867201d6f2b Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 23 Nov 2021 20:00:07 +1300
Subject: [PATCH 40/99] kdc: Match Windows error code for mismatching sname

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit b6a25f5f016aef39c3b1d7be8b3ecfe021c03c83)
---
 selftest/knownfail_heimdal_kdc | 3 ---
 source4/kdc/db-glue.c          | 2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index fd05719cc4c..d89d69deed2 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -81,7 +81,6 @@
 ^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_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_wrong_sname
 #
 ^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
@@ -130,6 +129,4 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index d017741e30a..bed0ff773f9 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -2599,7 +2599,7 @@ samba_kdc_check_s4u2self(krb5_context context,
 	 */
 	if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
 		talloc_free(frame);
-		return KRB5KDC_ERR_BADOPTION;
+		return KRB5KRB_AP_ERR_BADMATCH;
 	}
 
 	talloc_free(frame);
-- 
2.25.1


From 0368939b7d60c08aa8f84dbb53a88d5c9ec96058 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 23 Nov 2021 20:15:41 +1300
Subject: [PATCH 41/99] kdc: Always add the PAC if the header TGT is from an
 RODC

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 690a00a40c0a3f77da6e4dca42b630f2793a98b8)
---
 selftest/knownfail_heimdal_kdc | 1 -
 source4/kdc/wdc-samba4.c       | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index d89d69deed2..3b78491c837 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -128,5 +128,4 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c
index ecd182702c3..8c3ce71529c 100644
--- a/source4/kdc/wdc-samba4.c
+++ b/source4/kdc/wdc-samba4.c
@@ -471,7 +471,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
 		goto out;
 	}
 
-	if (!server_skdc_entry->is_krbtgt) {
+	if (!is_untrusted && !server_skdc_entry->is_krbtgt) {
 		/*
 		 * The client may have requested no PAC when obtaining the
 		 * TGT.
-- 
2.25.1


From 2903a913bf3ca96b9dd3f636b05530adc6e7994f Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 25 Nov 2021 10:32:44 +1300
Subject: [PATCH 42/99] tests/krb5: Add tests for renewal and validation of
 RODC TGTs with PAC requests

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 73a48063469205099f02efdf3b8f0f1040dc7a3d)
---
 python/samba/tests/krb5/kdc_tgs_tests.py | 90 ++++++++++++++++++++++++
 selftest/knownfail_heimdal_kdc           |  6 ++
 selftest/knownfail_mit_kdc               |  6 ++
 3 files changed, 102 insertions(+)

diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index ecc38538e61..2923d53772a 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -1867,6 +1867,51 @@ class KdcTgsTests(KDCBaseTest):
         pac = self.get_ticket_pac(ticket)
         self.assertIsNotNone(pac)
 
+    def test_rodc_renew_pac_request_none(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self.get_tgt(creds, pac_request=None)
+        tgt = self._modify_tgt(tgt, renewable=True, from_rodc=True)
+
+        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None,
+                              expect_pac_attrs=False,
+                              expect_requester_sid=True)
+
+        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
+    def test_rodc_renew_pac_request_false(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+        tgt = self._modify_tgt(tgt, renewable=True, from_rodc=True)
+
+        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None,
+                              expect_pac_attrs=False,
+                              expect_requester_sid=True)
+
+        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
+    def test_rodc_renew_pac_request_true(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self.get_tgt(creds, pac_request=True)
+        tgt = self._modify_tgt(tgt, renewable=True, from_rodc=True)
+
+        tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None,
+                              expect_pac_attrs=False,
+                              expect_requester_sid=True)
+
+        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
     def test_validate_pac_request_none(self):
         creds = self._get_creds()
         tgt = self.get_tgt(creds, pac_request=None)
@@ -1912,6 +1957,51 @@ class KdcTgsTests(KDCBaseTest):
         pac = self.get_ticket_pac(ticket)
         self.assertIsNotNone(pac)
 
+    def test_rodc_validate_pac_request_none(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self.get_tgt(creds, pac_request=None)
+        tgt = self._modify_tgt(tgt, invalid=True, from_rodc=True)
+
+        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None,
+                                 expect_pac_attrs=False,
+                                 expect_requester_sid=True)
+
+        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
+    def test_rodc_validate_pac_request_false(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+        tgt = self._modify_tgt(tgt, invalid=True, from_rodc=True)
+
+        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None,
+                                 expect_pac_attrs=False,
+                                 expect_requester_sid=True)
+
+        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
+    def test_rodc_validate_pac_request_true(self):
+        creds = self._get_creds(replication_allowed=True,
+                                revealed_to_rodc=True)
+        tgt = self.get_tgt(creds, pac_request=True)
+        tgt = self._modify_tgt(tgt, invalid=True, from_rodc=True)
+
+        tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None,
+                                 expect_pac_attrs=False,
+                                 expect_requester_sid=True)
+
+        ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+        pac = self.get_ticket_pac(ticket)
+        self.assertIsNotNone(pac)
+
     def test_s4u2self_pac_request_none(self):
         creds = self._get_creds()
         tgt = self.get_tgt(creds, pac_request=None)
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 3b78491c837..cc2396b2d38 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -116,6 +116,12 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 806aaa707d7..36be42d0481 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -400,6 +400,12 @@ 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_renew_rodc_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_service_ticket
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req(?!_invalid)
-- 
2.25.1


From 81a6fa876fd48af9998ee209d96e3cde1511e9f5 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 25 Nov 2021 13:24:57 +1300
Subject: [PATCH 43/99] Revert "CVE-2020-25719 s4/torture: Expect additional
 PAC buffers"

This reverts commit fa4c9bcefdeed0a7106aab84df20b02435febc1f.

We should not be generating these additional PAC buffers for service
tickets, only for TGTs.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit e61983c7f2c4daade83b237efb990d0c0645b3a3)
---
 selftest/knownfail_heimdal_kdc   | 39 ++++++++++++++++++++++++++++++++
 source4/torture/rpc/remote_pac.c | 24 ++------------------
 2 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index cc2396b2d38..1e42007f31f 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -135,3 +135,42 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
+#
+# PAC tests
+#
+^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 5a1567f1bde..16249799e36 100644
--- a/source4/torture/rpc/remote_pac.c
+++ b/source4/torture/rpc/remote_pac.c
@@ -308,7 +308,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 = 7;
+	num_pac_buffers = 5;
 	if (expect_pac_upn_dns_info) {
 		num_pac_buffers += 1;
 	}
@@ -365,18 +365,6 @@ static bool test_PACVerify(struct torture_context *tctx,
 		       pac_buf->info != NULL,
 		       "PAC_TYPE_TICKET_CHECKSUM info");
 
-	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_ATTRIBUTES_INFO);
-	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_ATTRIBUTES_INFO");
-	torture_assert(tctx,
-		       pac_buf->info != NULL,
-		       "PAC_TYPE_ATTRIBUTES_INFO info");
-
-	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_REQUESTER_SID);
-	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_REQUESTER_SID");
-	torture_assert(tctx,
-		       pac_buf->info != NULL,
-		       "PAC_TYPE_REQUESTER_SID info");
-
 	ok = netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
 				   negotiate_flags, pac_data, session_info);
 
@@ -1140,7 +1128,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 = 9;
+	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");
@@ -1180,14 +1168,6 @@ static bool test_S4U2Proxy(struct torture_context *tctx,
 				 talloc_asprintf(tctx, "%s@%s", self_princ, cli_credentials_get_realm(credentials)),
 				 "wrong transited_services[0]");
 
-	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_ATTRIBUTES_INFO);
-	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_ATTRIBUTES_INFO");
-	torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_ATTRIBUTES_INFO info");
-
-	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_REQUESTER_SID);
-	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_REQUESTER_SID");
-	torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_REQUESTER_SID info");
-
 	return netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
 				     negotiate_flags, pac_data, session_info);
 }
-- 
2.25.1


From 88b71db4bb8315c6d53c820bfc7b680bf04114a9 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 20:42:22 +1300
Subject: [PATCH 44/99] kdc: Don't include extra PAC buffers in service tickets

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 90025b6a4d250a15c0f988a9a9150ecfb63069ef)
---
 selftest/knownfail_heimdal_kdc | 42 ----------------------------------
 source4/kdc/wdc-samba4.c       | 31 +++++++++++++++++--------
 2 files changed, 21 insertions(+), 52 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 1e42007f31f..219ab11e16a 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -123,11 +123,8 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid(?!_)
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_validate
@@ -135,42 +132,3 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
-#
-# PAC tests
-#
-^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/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c
index 8c3ce71529c..17af76f4edb 100644
--- a/source4/kdc/wdc-samba4.c
+++ b/source4/kdc/wdc-samba4.c
@@ -132,6 +132,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
 	krb5_error_code ret;
 	NTSTATUS nt_status;
 	bool is_in_db, is_untrusted;
+	bool is_krbtgt;
 	size_t num_types = 0;
 	uint32_t *types = NULL;
 	uint32_t forced_next_type = 0;
@@ -471,7 +472,9 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
 		goto out;
 	}
 
-	if (!is_untrusted && !server_skdc_entry->is_krbtgt) {
+	is_krbtgt = krb5_principal_is_krbtgt(context, server->entry.principal);
+
+	if (!is_untrusted && !is_krbtgt) {
 		/*
 		 * The client may have requested no PAC when obtaining the
 		 * TGT.
@@ -576,17 +579,25 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
 			type_blob = data_blob_const(&zero_byte, 1);
 			break;
 		case PAC_TYPE_ATTRIBUTES_INFO:
-			/* just copy... */
-			break;
+			if (is_krbtgt) {
+				/* just copy... */
+				break;
+			} else {
+				continue;
+			}
 		case PAC_TYPE_REQUESTER_SID:
-			/*
-			 * Replace in the RODC case, otherwise
-			 * requester_sid_blob is NULL and we just copy.
-			 */
-			if (requester_sid_blob != NULL) {
-				type_blob = *requester_sid_blob;
+			if (is_krbtgt) {
+				/*
+				 * Replace in the RODC case, otherwise
+				 * requester_sid_blob is NULL and we just copy.
+				 */
+				if (requester_sid_blob != NULL) {
+					type_blob = *requester_sid_blob;
+				}
+				break;
+			} else {
+				continue;
 			}
-			break;
 		default:
 			/* just copy... */
 			break;
-- 
2.25.1


From 081d6b571a81266b39b0efb70c1de492e3d60ae0 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 25 Nov 2021 10:53:49 +1300
Subject: [PATCH 45/99] kdc: Remove PAC_TYPE_ATTRIBUTES_INFO from RODC-issued
 tickets

Windows ignores PAC_TYPE_ATTRIBUTES_INFO and always issues a PAC when
presented with an RODC-issued TGT. By removing this PAC buffer from
RODC-issued tickets, we ensure that an RODC-issued ticket will still
result in a PAC if it is first renewed or validated by the main DC.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 4b60e9516497c2e7f1545fe50887d0336b9893f2)
---
 selftest/knownfail_heimdal_kdc | 13 -------------
 source4/kdc/wdc-samba4.c       |  2 +-
 2 files changed, 1 insertion(+), 14 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 219ab11e16a..7dccc3d4c0d 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -112,16 +112,6 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_revealed
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_renew_pac_request_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
@@ -129,6 +119,3 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c
index 17af76f4edb..713720bcb99 100644
--- a/source4/kdc/wdc-samba4.c
+++ b/source4/kdc/wdc-samba4.c
@@ -579,7 +579,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
 			type_blob = data_blob_const(&zero_byte, 1);
 			break;
 		case PAC_TYPE_ATTRIBUTES_INFO:
-			if (is_krbtgt) {
+			if (!is_untrusted && is_krbtgt) {
 				/* just copy... */
 				break;
 			} else {
-- 
2.25.1


From 992a924dfa401daa630931c5dbec2fe9537c7ea9 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 25 Nov 2021 12:46:40 +1300
Subject: [PATCH 46/99] tests/krb5: Add a test for S4U2Self with no
 authorization data required

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 192d6edfe912105ec344dc554f872a24c03540a3)
---
 python/samba/tests/krb5/s4u_tests.py | 34 ++++++++++++++++++++++++++++
 selftest/knownfail_heimdal_kdc       |  1 +
 2 files changed, 35 insertions(+)

diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py
index 2953766ef21..6ec9af11423 100755
--- a/python/samba/tests/krb5/s4u_tests.py
+++ b/python/samba/tests/krb5/s4u_tests.py
@@ -324,6 +324,13 @@ class S4UKerberosTests(KDCBaseTest):
                                    sname=service_sname,
                                    etypes=etypes)
 
+        if not expected_error_mode:
+            # Check that the ticket contains a PAC.
+            ticket = kdc_exchange_dict['rep_ticket_creds']
+
+            pac = self.get_ticket_pac(ticket)
+            self.assertIsNotNone(pac)
+
         # Ensure we used all the parameters given to us.
         self.assertEqual({}, kdc_dict)
 
@@ -504,6 +511,24 @@ class S4UKerberosTests(KDCBaseTest):
                     self.set_ticket_forwardable, flag=True)
             })
 
+    # Do an S4U2Self where the service does not require authorization data. The
+    # resulting ticket should still contain a PAC.
+    def test_s4u2self_no_auth_data_required(self):
+        self._run_s4u2self_test(
+            {
+                'client_opts': {
+                    'not_delegated': False
+                },
+                'service_opts': {
+                    'trusted_to_auth_for_delegation': True,
+                    'no_auth_data_required': True
+                },
+                '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(
@@ -654,6 +679,15 @@ class S4UKerberosTests(KDCBaseTest):
                                    etypes=etypes,
                                    additional_tickets=additional_tickets)
 
+        if not expected_error_mode:
+            # Check whether the ticket contains a PAC.
+            ticket = kdc_exchange_dict['rep_ticket_creds']
+            pac = self.get_ticket_pac(ticket, expect_pac=expect_pac)
+            if expect_pac:
+                self.assertIsNotNone(pac)
+            else:
+                self.assertIsNone(pac)
+
         # Ensure we used all the parameters given to us.
         self.assertEqual({}, kdc_dict)
 
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 7dccc3d4c0d..363107f476e 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -80,6 +80,7 @@
 ^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_forwardable
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_no_auth_data_required
 ^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_constrained_delegation_no_auth_data_required
-- 
2.25.1


From 5e6c25f1ed08045f5341e425621e32a75e84ff27 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 23 Nov 2021 17:30:50 +1300
Subject: [PATCH 47/99] heimdal:kdc: Always generate a PAC for S4U2Self

If we decided not to put a PAC into the ticket, mspac would be NULL
here, and the resulting ticket would not contain a PAC. This could
happen if there was a request to omit the PAC or the service did not
require authorization data. Ensure that we always generate a PAC.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 1f4f3018c5001b289b91959a72d00575c8fc0ac1)
---
 selftest/knownfail_heimdal_kdc |  2 --
 source4/heimdal/kdc/krb5tgs.c  | 13 +++++++------
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 363107f476e..ace0550fd15 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -80,7 +80,6 @@
 ^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_forwardable
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_no_auth_data_required
 ^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_constrained_delegation_no_auth_data_required
@@ -113,7 +112,6 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index 6c5c51aa448..dc356b4daa5 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -1846,12 +1846,13 @@ server_lookup:
 	    if (mspac) {
 		krb5_pac_free(context, mspac);
 		mspac = NULL;
-		ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
-		if (ret) {
-		    kdc_log(context, config, 0, "PAC generation failed for -- %s",
-			    tpn);
-		    goto out;
-		}
+	    }
+
+	    ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
+	    if (ret) {
+		kdc_log(context, config, 0, "PAC generation failed for -- %s",
+			tpn);
+		goto out;
 	    }
 
 	    /*
-- 
2.25.1


From 612c769ab7061906f2089e7af15c3745be610201 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 25 Nov 2021 09:29:42 +1300
Subject: [PATCH 48/99] selftest: Properly check extra PAC buffers with Heimdal

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit ee4aa21c487fa80082a548b2e4f115a791e30340)
---
 selftest/knownfail_heimdal_kdc | 12 ++++++++++++
 source4/selftest/tests.py      |  2 +-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index ace0550fd15..4d7d6a67b92 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -79,8 +79,15 @@
 ^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_no_auth_data_required
+^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
 #
 ^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
@@ -112,6 +119,11 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req(?!_invalid)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 7234767baa5..f2ea9adb67f 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -905,7 +905,7 @@ for env in ['fileserver_smb1', 'nt4_member', 'clusteredmember', 'ktest', 'nt4_dc
 have_fast_support = int('SAMBA_USES_MITKDC' in config_hash)
 tkt_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash)
 expect_pac = int('SAMBA4_USES_HEIMDAL' in config_hash)
-extra_pac_buffers = 0
+extra_pac_buffers = 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 0426d20aeabba4dbd76bffbadd97a5c8afe2091e Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 23 Nov 2021 19:38:35 +1300
Subject: [PATCH 49/99] heimdal:kdc: Do not generate extra PAC buffers for
 S4U2Self service ticket

Normally samba_wdc_get_pac() is used to generate the PAC for a TGT, but
when generating a service ticket for S4U2Self, we want to avoid adding
the additional PAC_ATTRIBUTES_INFO and PAC_REQUESTER_SID buffers.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 9bd26804852d957f81cb311e5142f9190f9afa65)
---
 selftest/knownfail_heimdal_kdc     | 12 ------------
 source4/heimdal/kdc/kerberos5.c    |  2 +-
 source4/heimdal/kdc/krb5tgs.c      |  3 ++-
 source4/heimdal/kdc/windc.c        |  5 +++--
 source4/heimdal/kdc/windc_plugin.h |  2 ++
 source4/kdc/wdc-samba4.c           | 11 ++++++++---
 6 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 4d7d6a67b92..ace0550fd15 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -79,15 +79,8 @@
 ^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_no_auth_data_required
-^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
 #
 ^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
@@ -119,11 +112,6 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req(?!_invalid)
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_revealed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
index 11b334e46fe..ad026dd617b 100644
--- a/source4/heimdal/kdc/kerberos5.c
+++ b/source4/heimdal/kdc/kerberos5.c
@@ -1777,7 +1777,7 @@ _kdc_as_rep(krb5_context context,
 
 	sent_pac_request = send_pac_p(context, req, &pac_request);
 
-	ret = _kdc_pac_generate(context, client, pk_reply_key,
+	ret = _kdc_pac_generate(context, client, server, pk_reply_key,
 				sent_pac_request ? &pac_request : NULL,
 				&p);
 	if (ret) {
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index dc356b4daa5..38dba8493ae 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -1848,7 +1848,8 @@ server_lookup:
 		mspac = NULL;
 	    }
 
-	    ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
+	    ret = _kdc_pac_generate(context, s4u2self_impersonated_client, server,
+				    NULL, NULL, &mspac);
 	    if (ret) {
 		kdc_log(context, config, 0, "PAC generation failed for -- %s",
 			tpn);
diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c
index 93b973f576b..0a5ae5025ec 100644
--- a/source4/heimdal/kdc/windc.c
+++ b/source4/heimdal/kdc/windc.c
@@ -73,6 +73,7 @@ krb5_kdc_windc_init(krb5_context context)
 krb5_error_code
 _kdc_pac_generate(krb5_context context,
 		  hdb_entry_ex *client,
+		  hdb_entry_ex *server,
 		  const krb5_keyblock *pk_reply_key,
 		  const krb5_boolean *pac_request,
 		  krb5_pac *pac)
@@ -88,9 +89,9 @@ _kdc_pac_generate(krb5_context context,
 
     if (windcft->pac_pk_generate != NULL && pk_reply_key != NULL)
 	return (windcft->pac_pk_generate)(windcctx, context,
-					  client, pk_reply_key,
+					  client, server, pk_reply_key,
 					  pac_request, pac);
-    return (windcft->pac_generate)(windcctx, context, client,
+    return (windcft->pac_generate)(windcctx, context, client, server,
 				   pac_request, pac);
 }
 
diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h
index c7f2bcb5ed9..d239d0260e7 100644
--- a/source4/heimdal/kdc/windc_plugin.h
+++ b/source4/heimdal/kdc/windc_plugin.h
@@ -55,12 +55,14 @@ struct hdb_entry_ex;
 typedef krb5_error_code
 (*krb5plugin_windc_pac_generate)(void *, krb5_context,
 				 struct hdb_entry_ex *, /* client */
+				 struct hdb_entry_ex *, /* server */
 				 const krb5_boolean *, /* pac_request */
 				 krb5_pac *);
 
 typedef krb5_error_code
 (*krb5plugin_windc_pac_pk_generate)(void *, krb5_context,
 				    struct hdb_entry_ex *, /* client */
+				    struct hdb_entry_ex *, /* server */
 				    const krb5_keyblock *, /* pk_replykey */
 				    const krb5_boolean *, /* pac_request */
 				    krb5_pac *);
diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c
index 713720bcb99..b1d011c09a9 100644
--- a/source4/kdc/wdc-samba4.c
+++ b/source4/kdc/wdc-samba4.c
@@ -37,6 +37,7 @@
  */
 static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
 					 struct hdb_entry_ex *client,
+					 struct hdb_entry_ex *server,
 					 const krb5_keyblock *pk_reply_key,
 					 const krb5_boolean *pac_request,
 					 krb5_pac *pac)
@@ -55,6 +56,7 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
 	struct samba_kdc_entry *skdc_entry =
 		talloc_get_type_abort(client->ctx,
 		struct samba_kdc_entry);
+	bool is_krbtgt;
 
 	mem_ctx = talloc_named(client->ctx, 0, "samba_get_pac context");
 	if (!mem_ctx) {
@@ -65,13 +67,15 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
 		cred_ndr_ptr = &cred_ndr;
 	}
 
+	is_krbtgt = krb5_principal_is_krbtgt(context, server->entry.principal);
+
 	nt_status = samba_kdc_get_pac_blobs(mem_ctx, skdc_entry,
 					    &logon_blob,
 					    cred_ndr_ptr,
 					    &upn_blob,
-					    &pac_attrs_blob,
+					    is_krbtgt ? &pac_attrs_blob : NULL,
 					    pac_request,
-					    &requester_sid_blob,
+					    is_krbtgt ? &requester_sid_blob : NULL,
 					    NULL);
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		talloc_free(mem_ctx);
@@ -101,10 +105,11 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
 
 static krb5_error_code samba_wdc_get_pac_compat(void *priv, krb5_context context,
 						struct hdb_entry_ex *client,
+						struct hdb_entry_ex *server,
 						const krb5_boolean *pac_request,
 						krb5_pac *pac)
 {
-	return samba_wdc_get_pac(priv, context, client, NULL, pac_request, pac);
+	return samba_wdc_get_pac(priv, context, client, server, NULL, pac_request, pac);
 }
 
 static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
-- 
2.25.1


From 2eef0f950bc8c2ed2309798a75d88823a81eefff Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 24 Nov 2021 20:41:54 +1300
Subject: [PATCH 50/99] kdc: Require that PAC_REQUESTER_SID buffer is present
 for TGTs

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>

Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Tue Nov 30 03:33:26 UTC 2021 on sn-devel-184

(cherry picked from commit 38c5bad4a853b19fe9a51fb059e150b153c4632a)
---
 selftest/knownfail_heimdal_kdc | 6 ------
 source4/kdc/wdc-samba4.c       | 6 ++++++
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index ace0550fd15..e9a560555da 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -112,9 +112,3 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_validate
diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c
index b1d011c09a9..d7ce34fb3a9 100644
--- a/source4/kdc/wdc-samba4.c
+++ b/source4/kdc/wdc-samba4.c
@@ -459,6 +459,12 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
 		talloc_free(mem_ctx);
 		return EINVAL;
 	}
+	if (delegated_proxy_principal == NULL && requester_sid_idx == -1) {
+		DEBUG(1, ("PAC_TYPE_REQUESTER_SID missing\n"));
+		SAFE_FREE(types);
+		talloc_free(mem_ctx);
+		return KRB5KDC_ERR_TGT_REVOKED;
+	}
 
 	/*
 	 * The server account may be set not to want the PAC.
-- 
2.25.1


From d34d201773ae9c05e424a5c5d568c94483f1be69 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 7 Dec 2021 13:15:38 +1300
Subject: [PATCH 51/99] kdc: Canonicalize realm for enterprise principals

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>

Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Tue Dec  7 04:54:35 UTC 2021 on sn-devel-184

(cherry picked from commit 8bd7b316bd61ef35f6e0baa0b65f0ef00910112c)
---
 selftest/knownfail.d/kdc-enterprise | 63 -----------------------------
 selftest/knownfail_heimdal_kdc      |  3 --
 selftest/knownfail_mit_kdc          | 36 +++++++++++++++++
 source4/kdc/db-glue.c               | 24 +++++------
 4 files changed, 47 insertions(+), 79 deletions(-)
 delete mode 100644 selftest/knownfail.d/kdc-enterprise

diff --git a/selftest/knownfail.d/kdc-enterprise b/selftest/knownfail.d/kdc-enterprise
deleted file mode 100644
index c9b6c98a2ee..00000000000
--- a/selftest/knownfail.d/kdc-enterprise
+++ /dev/null
@@ -1,63 +0,0 @@
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_RemoveDollar\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_NetbiosRealm\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN\(
-samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_UPN\(
-
-
-
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_RemoveDollar_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_AsReqSelf\(
-^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index e9a560555da..692b9ecdd72 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -5,9 +5,6 @@
 #
 # Heimdal currently fails the following MS-KILE client principal lookup
 # 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
-^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_4
-^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_5
 ^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_6_a
 ^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_enterprise_principal_step_6_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_a
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 36be42d0481..6a4ddaa00ec 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -56,17 +56,53 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_UPN\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_UPN_RemoveDollar\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_AsReqSelf\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_RemoveDollar\(
 samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_UPN\(
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index bed0ff773f9..5752ffb821c 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -980,19 +980,17 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 			goto out;
 		}
 
-		if (smb_krb5_principal_get_type(context, principal) != KRB5_NT_ENTERPRISE_PRINCIPAL) {
-			/* While we have copied the client principal, tests
-			 * show that Win2k3 returns the 'corrected' realm, not
-			 * the client-specified realm.  This code attempts to
-			 * replace the client principal's realm with the one
-			 * we determine from our records */
-			
-			/* this has to be with malloc() */
-			ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
-			if (ret) {
-				krb5_clear_error_message(context);
-				goto out;
-			}
+		/* While we have copied the client principal, tests
+		 * show that Win2k3 returns the 'corrected' realm, not
+		 * the client-specified realm.  This code attempts to
+		 * replace the client principal's realm with the one
+		 * we determine from our records */
+
+		/* this has to be with malloc() */
+		ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
+		if (ret) {
+			krb5_clear_error_message(context);
+			goto out;
 		}
 	}
 
-- 
2.25.1


From 3ac74c8b94d6c2d109ee07712f55be01190a6816 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 14 Dec 2021 19:16:00 +1300
Subject: [PATCH 52/99] tests/krb5: Correctly determine whether tickets are
 service tickets

Previously we expected tickets to contain a ticket checksum if the sname
was not the krbtgt. However, the ticket checksum should not be present
if we are performing an AS-REQ to our own account. Now we determine a
ticket is a service ticket only if the request is also a TGS-REQ.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit 100be7eb8e70ba270a8e92957a5e47466160a901)
---
 python/samba/tests/krb5/compatability_tests.py | 10 ++++++----
 python/samba/tests/krb5/kdc_base_test.py       |  2 +-
 python/samba/tests/krb5/raw_testcase.py        | 18 ++++++++++--------
 python/samba/tests/krb5/rodc_tests.py          |  4 ++--
 4 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/python/samba/tests/krb5/compatability_tests.py b/python/samba/tests/krb5/compatability_tests.py
index ed2dc565b6d..65e9e3788d5 100755
--- a/python/samba/tests/krb5/compatability_tests.py
+++ b/python/samba/tests/krb5/compatability_tests.py
@@ -132,13 +132,14 @@ class SimpleKerberosTests(KDCBaseTest):
         tgt = self.get_tgt(user_creds)
 
         # Ensure the PAC contains the expected checksums.
-        self.verify_ticket(tgt, key)
+        self.verify_ticket(tgt, key, service_ticket=False)
 
         # 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)
+        self.verify_ticket(service_ticket, key, service_ticket=True,
+                           expect_ticket_checksum=True)
 
     def test_mit_ticket_signature(self):
         # Ensure that a DC does not issue tickets signed with its krbtgt key.
@@ -152,13 +153,14 @@ class SimpleKerberosTests(KDCBaseTest):
         tgt = self.get_tgt(user_creds)
 
         # Ensure the PAC contains the expected checksums.
-        self.verify_ticket(tgt, key)
+        self.verify_ticket(tgt, key, service_ticket=False)
 
         # 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)
+        self.verify_ticket(service_ticket, key, service_ticket=True,
+                           expect_ticket_checksum=False)
 
     def as_pre_auth_req(self, creds, etypes):
         user = creds.get_username()
diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 6e96b982167..9506048ee2a 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -1395,7 +1395,7 @@ class KDCBaseTest(RawKerberosTest):
             krbtgt_creds = self.get_krbtgt_creds()
         krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
         self.verify_ticket(service_ticket_creds, krbtgt_key,
-                           expect_pac=expect_pac,
+                           service_ticket=True, expect_pac=expect_pac,
                            expect_ticket_checksum=self.tkt_sig_support)
 
         self.tkt_cache[cache_key] = service_ticket_creds
diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index 14e655313fc..a2241707d44 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -2587,7 +2587,11 @@ class RawKerberosTest(TestCaseInTempDir):
             self.assertIsNotNone(ticket_decryption_key)
 
         if ticket_decryption_key is not None:
-            self.verify_ticket(ticket_creds, krbtgt_keys, expect_pac=expect_pac,
+            service_ticket = (not self.is_tgs(expected_sname)
+                              and rep_msg_type == KRB_TGS_REP)
+            self.verify_ticket(ticket_creds, krbtgt_keys,
+                               service_ticket=service_ticket,
+                               expect_pac=expect_pac,
                                expect_ticket_checksum=expect_ticket_checksum
                                or self.tkt_sig_support)
 
@@ -2624,14 +2628,14 @@ class RawKerberosTest(TestCaseInTempDir):
                 expected_types.append(krb5pac.PAC_TYPE_DEVICE_INFO)
                 expected_types.append(krb5pac.PAC_TYPE_DEVICE_CLAIMS_INFO)
 
-        if not self.is_tgs(expected_sname):
+        if not self.is_tgs(expected_sname) and rep_msg_type == KRB_TGS_REP:
             expected_types.append(krb5pac.PAC_TYPE_TICKET_CHECKSUM)
 
         require_strict = {krb5pac.PAC_TYPE_CLIENT_CLAIMS_INFO}
         if not self.tkt_sig_support:
             require_strict.add(krb5pac.PAC_TYPE_TICKET_CHECKSUM)
 
-        expect_extra_pac_buffers = rep_msg_type == KRB_AS_REP
+        expect_extra_pac_buffers = self.is_tgs(expected_sname)
 
         expect_pac_attrs = kdc_exchange_dict['expect_pac_attrs']
 
@@ -3233,11 +3237,9 @@ class RawKerberosTest(TestCaseInTempDir):
                                         ticket_blob)
         self.assertEqual(expected_checksum, checksum)
 
-    def verify_ticket(self, ticket, krbtgt_keys, expect_pac=True,
+    def verify_ticket(self, ticket, krbtgt_keys, service_ticket,
+                      expect_pac=True,
                       expect_ticket_checksum=True):
-        # Check if the ticket is a TGT.
-        is_tgt = self.is_tgt(ticket)
-
         # Decrypt the ticket.
 
         key = ticket.decryption_key
@@ -3336,7 +3338,7 @@ class RawKerberosTest(TestCaseInTempDir):
                                         kdc_ctype,
                                         kdc_checksum)
 
-        if is_tgt:
+        if not service_ticket:
             self.assertNotIn(krb5pac.PAC_TYPE_TICKET_CHECKSUM, checksums)
         else:
             ticket_checksum, ticket_ctype = checksums.get(
diff --git a/python/samba/tests/krb5/rodc_tests.py b/python/samba/tests/krb5/rodc_tests.py
index 0e252d90262..83ee35d650a 100755
--- a/python/samba/tests/krb5/rodc_tests.py
+++ b/python/samba/tests/krb5/rodc_tests.py
@@ -58,14 +58,14 @@ class RodcKerberosTests(KDCBaseTest):
         tgt = self.get_tgt(user_creds, to_rodc=True)
 
         # Ensure the PAC contains the expected checksums.
-        self.verify_ticket(tgt, rodc_key)
+        self.verify_ticket(tgt, rodc_key, service_ticket=False)
 
         # 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)
+        self.verify_ticket(service_ticket, rodc_key, service_ticket=True)
 
 
 if __name__ == "__main__":
-- 
2.25.1


From 9a1bee7c95d04577ce129f86c0b23f4f73cd9aae Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 8 Feb 2022 12:15:36 +1300
Subject: [PATCH 53/99] tests/krb5: Add helper function to modify ticket flags

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
(cherry picked from commit ded5115f73dff5b8b2f3212988e03f9dbe0c2aa3)
---
 python/samba/tests/krb5/kdc_base_test.py | 14 ++++++++++++++
 python/samba/tests/krb5/kdc_tgs_tests.py | 18 ++----------------
 python/samba/tests/krb5/s4u_tests.py     | 17 +++--------------
 3 files changed, 19 insertions(+), 30 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 9506048ee2a..58b87eab25b 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -1602,6 +1602,20 @@ class KDCBaseTest(RawKerberosTest):
             enc_part, asn1Spec=krb5_asn1.EncTicketPart())
         return enc_ticket_part
 
+    def modify_ticket_flag(self, enc_part, flag, value):
+        self.assertIsInstance(value, bool)
+
+        flag = krb5_asn1.TicketFlags(flag)
+        pos = len(tuple(flag)) - 1
+
+        flags = enc_part['flags']
+        self.assertLessEqual(pos, len(flags))
+
+        new_flags = flags[:pos] + str(int(value)) + flags[pos + 1:]
+        enc_part['flags'] = new_flags
+
+        return enc_part
+
     def get_objectSid(self, samdb, dn):
         ''' Get the objectSID for a DN
             Note: performs an Ldb query.
diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 2923d53772a..8cd27dec2aa 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -2177,14 +2177,7 @@ class KdcTgsTests(KDCBaseTest):
 
     def _modify_renewable(self, enc_part):
         # Set the renewable flag.
-        renewable_flag = krb5_asn1.TicketFlags('renewable')
-        pos = len(tuple(renewable_flag)) - 1
-
-        flags = enc_part['flags']
-        self.assertLessEqual(pos, len(flags))
-
-        new_flags = flags[:pos] + '1' + flags[pos + 1:]
-        enc_part['flags'] = new_flags
+        enc_part = self.modify_ticket_flag(enc_part, 'renewable', value=True)
 
         # Set the renew-till time to be in the future.
         renew_till = self.get_KerberosTime(offset=100 * 60 * 60)
@@ -2194,14 +2187,7 @@ class KdcTgsTests(KDCBaseTest):
 
     def _modify_invalid(self, enc_part):
         # Set the invalid flag.
-        invalid_flag = krb5_asn1.TicketFlags('invalid')
-        pos = len(tuple(invalid_flag)) - 1
-
-        flags = enc_part['flags']
-        self.assertLessEqual(pos, len(flags))
-
-        new_flags = flags[:pos] + '1' + flags[pos + 1:]
-        enc_part['flags'] = new_flags
+        enc_part = self.modify_ticket_flag(enc_part, 'invalid', value=True)
 
         # Set the ticket start time to be in the past.
         past_time = self.get_KerberosTime(offset=-100 * 60 * 60)
diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py
index 6ec9af11423..49dd89cd764 100755
--- a/python/samba/tests/krb5/s4u_tests.py
+++ b/python/samba/tests/krb5/s4u_tests.py
@@ -1336,20 +1336,9 @@ class S4UKerberosTests(KDCBaseTest):
                                     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
+        modify_fn = functools.partial(self.modify_ticket_flag,
+                                      flag='forwardable',
+                                      value=flag)
 
         if update_pac_checksums:
             checksum_keys = self.get_krbtgt_checksum_key()
-- 
2.25.1


From 19d76f103100f1a915486eb0bad2264dd203e71e Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 4 Mar 2022 16:57:27 +1300
Subject: [PATCH 54/99] selftest: Simplify krb5 test environments

It's not necessary to repeat the required environment variables for
every test.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
(cherry picked from commit e729606631b5bfaf7c4ad8c1e70697adf8274777)

[jsutton@samba.org Fixed conflicts caused by missing check_cname,
 check_padata and fast_support variables]
---
 source4/selftest/tests.py | 191 +++++++-------------------------------
 1 file changed, 35 insertions(+), 156 deletions(-)

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index f2ea9adb67f..dc340623f3e 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -903,106 +903,59 @@ for env in ['fileserver_smb1', 'nt4_member', 'clusteredmember', 'ktest', 'nt4_dc
     planoldpythontestsuite(env, "samba.tests.imports")
 
 have_fast_support = int('SAMBA_USES_MITKDC' in config_hash)
+claims_support = 0
+compound_id_support = 0
 tkt_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash)
 expect_pac = int('SAMBA4_USES_HEIMDAL' in config_hash)
 extra_pac_buffers = int('SAMBA4_USES_HEIMDAL' in config_hash)
+krb5_environ = {
+    'SERVICE_USERNAME': '$SERVER',
+    'ADMIN_USERNAME': '$DC_USERNAME',
+    'ADMIN_PASSWORD': '$DC_PASSWORD',
+    'FOR_USER': '$DC_USERNAME',
+    'STRICT_CHECKING':'0',
+    'FAST_SUPPORT': have_fast_support,
+    'CLAIMS_SUPPORT': claims_support,
+    'COMPOUND_ID_SUPPORT': compound_id_support,
+    'TKT_SIG_SUPPORT': tkt_sig_support,
+    'EXPECT_PAC': expect_pac,
+    'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers,
+}
 planoldpythontestsuite("none", "samba.tests.krb5.kcrypto")
 planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.simple_tests",
-                       environ={'SERVICE_USERNAME':'$SERVER',
-                                'FAST_SUPPORT': have_fast_support,
-                                'TKT_SIG_SUPPORT': tkt_sig_support,
-                                'EXPECT_PAC': expect_pac,
-                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
+                       environ=krb5_environ)
 planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests",
-                       environ={'ADMIN_USERNAME':'$USERNAME',
-                                'ADMIN_PASSWORD':'$PASSWORD',
-                                'FOR_USER':'$USERNAME',
-                                'STRICT_CHECKING':'0',
-                                'FAST_SUPPORT': have_fast_support,
-                                'TKT_SIG_SUPPORT': tkt_sig_support,
-                                'EXPECT_PAC': expect_pac,
-                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
+                       environ=krb5_environ)
 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,
-                                'EXPECT_PAC': expect_pac,
-                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
+                       environ=krb5_environ)
 
 planoldpythontestsuite("ad_dc_default", "samba.tests.dsdb_dns")
 
 planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests",
-                       environ={'FAST_SUPPORT': have_fast_support,
-                                'TKT_SIG_SUPPORT': tkt_sig_support,
-                                'EXPECT_PAC': expect_pac,
-                                'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
+                       environ=krb5_environ)
 
 planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ccache",
-                       environ={
-                           'ADMIN_USERNAME': '$USERNAME',
-                           'ADMIN_PASSWORD': '$PASSWORD',
-                           'STRICT_CHECKING': '0',
-                           'FAST_SUPPORT': have_fast_support,
-                           'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac,
-                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                       })
+                       environ=krb5_environ)
 planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap",
-                       environ={
-                           'ADMIN_USERNAME': '$USERNAME',
-                           'ADMIN_PASSWORD': '$PASSWORD',
-                           'STRICT_CHECKING': '0',
-                           'FAST_SUPPORT': have_fast_support,
-                           'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac,
-                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                       })
+                       environ=krb5_environ)
 for env in ['ad_dc_default', 'ad_member']:
     planoldpythontestsuite(env, "samba.tests.krb5.test_rpc",
-                           environ={
-                               'ADMIN_USERNAME': '$DC_USERNAME',
-                               'ADMIN_PASSWORD': '$DC_PASSWORD',
-                               'STRICT_CHECKING': '0',
-                               'FAST_SUPPORT': have_fast_support,
-                               'TKT_SIG_SUPPORT': tkt_sig_support,
-                               'EXPECT_PAC': expect_pac,
-                               'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                           })
+                           environ=krb5_environ)
 planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb",
-                       environ={
-                           'ADMIN_USERNAME': '$USERNAME',
-                           'ADMIN_PASSWORD': '$PASSWORD',
-                           'STRICT_CHECKING': '0',
-                           'FAST_SUPPORT': have_fast_support,
-                           'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac,
-                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                       })
+                       environ=krb5_environ)
 planoldpythontestsuite("ad_member_idmap_nss:local",
                        "samba.tests.krb5.test_min_domain_uid",
-                       environ={
-                           'ADMIN_USERNAME': '$DC_USERNAME',
-                           'ADMIN_PASSWORD': '$DC_PASSWORD',
-                           'STRICT_CHECKING': '0'
-                       })
+                       environ=krb5_environ)
 planoldpythontestsuite("ad_member_idmap_nss:local",
                        "samba.tests.krb5.test_idmap_nss",
                        environ={
-                           'ADMIN_USERNAME': '$DC_USERNAME',
-                           'ADMIN_PASSWORD': '$DC_PASSWORD',
+                           **krb5_environ,
                            'MAPPED_USERNAME': 'bob',
                            'MAPPED_PASSWORD': 'Secret007',
                            'UNMAPPED_USERNAME': 'jane',
                            'UNMAPPED_PASSWORD': 'Secret007',
                            'INVALID_USERNAME': 'joe',
                            'INVALID_PASSWORD': 'Secret007',
-                           'STRICT_CHECKING': '0',
-                           'FAST_SUPPORT': have_fast_support,
-                           'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac,
-                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
                        })
 
 for env in ["ad_dc", smbv1_disabled_testenv]:
@@ -1591,26 +1544,10 @@ plansmbtorture4testsuite('krb5.kdc', env, ['ncacn_np:$SERVER_IP', "-k", "yes", '
                          "samba4.krb5.kdc with account having identical UPN and SPN")
 for env in ["fl2008r2dc", "fl2003dc"]:
     planoldpythontestsuite(env, "samba.tests.krb5.as_req_tests",
-                           environ={
-                               'ADMIN_USERNAME': '$USERNAME',
-                               'ADMIN_PASSWORD': '$PASSWORD',
-                               'STRICT_CHECKING': '0',
-                               'FAST_SUPPORT': have_fast_support,
-                               'TKT_SIG_SUPPORT': tkt_sig_support,
-                               'EXPECT_PAC': expect_pac,
-                               'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                           })
+                           environ=krb5_environ)
 
 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,
-                           'EXPECT_PAC': expect_pac,
-                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                       })
+                       environ=krb5_environ)
 
 for env in ["rodc", "promoted_dc", "fl2000dc", "fl2008r2dc"]:
     if env == "rodc":
@@ -1627,89 +1564,31 @@ for env in ["rodc", "promoted_dc", "fl2000dc", "fl2008r2dc"]:
                              "samba4.krb5.kdc with machine account")
 
 planpythontestsuite("ad_dc", "samba.tests.krb5.as_canonicalization_tests",
-                       environ={
-                           'ADMIN_USERNAME': '$USERNAME',
-                           'ADMIN_PASSWORD': '$PASSWORD',
-                           'FAST_SUPPORT': have_fast_support,
-                           'TKT_SIG_SUPPORT': tkt_sig_support,
-                           'EXPECT_PAC': expect_pac,
-                           'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                       })
+                    environ=krb5_environ)
 planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests",
-                    environ={
-                        'ADMIN_USERNAME': '$USERNAME',
-                        'ADMIN_PASSWORD': '$PASSWORD',
-                        'STRICT_CHECKING': '0',
-                        'FAST_SUPPORT': have_fast_support,
-                        'TKT_SIG_SUPPORT': tkt_sig_support,
-                        'EXPECT_PAC': expect_pac,
-                        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-                    })
+                    environ=krb5_environ)
 planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests",
-                    environ={'FAST_SUPPORT': have_fast_support,
-                             'TKT_SIG_SUPPORT': tkt_sig_support,
-                             'EXPECT_PAC': expect_pac,
-                             'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers})
+                    environ=krb5_environ)
 planpythontestsuite(
     "ad_dc",
     "samba.tests.krb5.kdc_tgs_tests",
-    environ={
-        'ADMIN_USERNAME': '$USERNAME',
-        'ADMIN_PASSWORD': '$PASSWORD',
-        'STRICT_CHECKING': '0',
-        'FAST_SUPPORT': have_fast_support,
-        'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac,
-        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-    })
+    environ=krb5_environ)
 planpythontestsuite(
     "ad_dc",
     "samba.tests.krb5.fast_tests",
-    environ={
-        'ADMIN_USERNAME': '$USERNAME',
-        'ADMIN_PASSWORD': '$PASSWORD',
-        'STRICT_CHECKING': '0',
-        'FAST_SUPPORT': have_fast_support,
-        'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac,
-        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-    })
+    environ=krb5_environ)
 planpythontestsuite(
     "ad_dc",
     "samba.tests.krb5.ms_kile_client_principal_lookup_tests",
-    environ={
-        'ADMIN_USERNAME': '$USERNAME',
-        'ADMIN_PASSWORD': '$PASSWORD',
-        'STRICT_CHECKING': '0',
-        'FAST_SUPPORT': have_fast_support,
-        'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac,
-        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-    })
+    environ=krb5_environ)
 planpythontestsuite(
     "ad_dc",
     "samba.tests.krb5.spn_tests",
-    environ={
-        'ADMIN_USERNAME': '$USERNAME',
-        'ADMIN_PASSWORD': '$PASSWORD',
-        'STRICT_CHECKING': '0',
-        'FAST_SUPPORT': have_fast_support,
-        'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac,
-        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-    })
+    environ=krb5_environ)
 planpythontestsuite(
     "ad_dc",
     "samba.tests.krb5.alias_tests",
-    environ={
-        'ADMIN_USERNAME': '$USERNAME',
-        'ADMIN_PASSWORD': '$PASSWORD',
-        'STRICT_CHECKING': '0',
-        'FAST_SUPPORT': have_fast_support,
-        'TKT_SIG_SUPPORT': tkt_sig_support,
-        'EXPECT_PAC': expect_pac,
-        'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers
-    })
+    environ=krb5_environ)
 
 for env in [
         'vampire_dc',
-- 
2.25.1


From 8f4b78907bbfe915988d52724c66dae0e2eefa9b Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 15 Jun 2022 19:37:39 +1200
Subject: [PATCH 55/99] CVE-2022-2031 s4:kdc: Add MIT support for
 ATTRIBUTES_INFO and REQUESTER_SID PAC buffers

So that we do not confuse TGTs and kpasswd tickets, it is critical to
check that the REQUESTER_SID buffer exists in TGTs, and to ensure that
it is not propagated to service tickets.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>

[jsutton@samba.org Brought in changes to add ATTRIBUTES_INFO and
 REQUESTER_SID buffers to new PACs, and updated knownfails]
---
 selftest/knownfail_mit_kdc               | 17 -----
 source4/kdc/mit-kdb/kdb_samba_policies.c |  5 +-
 source4/kdc/mit_samba.c                  | 93 +++++++++++++++++++++++-
 source4/kdc/mit_samba.h                  |  1 +
 4 files changed, 94 insertions(+), 22 deletions(-)

diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 6a4ddaa00ec..095da10238c 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -423,7 +423,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_fast_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_pac_request_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_pac_request_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_req
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied
@@ -459,7 +458,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_tgs_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rename
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_no_requester_sid
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_krbtgt_link
@@ -490,7 +488,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_user2user_wrong_srealm
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_pac_request_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_pac_request_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_req
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied
@@ -508,21 +505,17 @@ 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_pac_attrs_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_false
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_pac_attrs
 #
@@ -537,21 +530,11 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 #
 # PAC requester SID tests
 #
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_as_requester_sid
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_sid_mismatch_nonexisting
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_existing
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_validate
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_validate
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_sid_mismatch_existing
diff --git a/source4/kdc/mit-kdb/kdb_samba_policies.c b/source4/kdc/mit-kdb/kdb_samba_policies.c
index f35210669c2..dada3b79144 100644
--- a/source4/kdc/mit-kdb/kdb_samba_policies.c
+++ b/source4/kdc/mit-kdb/kdb_samba_policies.c
@@ -162,6 +162,7 @@ done:
 
 static krb5_error_code ks_get_pac(krb5_context context,
 				  krb5_db_entry *client,
+				  krb5_db_entry *server,
 				  krb5_keyblock *client_key,
 				  krb5_pac *pac)
 {
@@ -176,6 +177,7 @@ static krb5_error_code ks_get_pac(krb5_context context,
 	code = mit_samba_get_pac(mit_ctx,
 				 context,
 				 client,
+				 server,
 				 client_key,
 				 pac);
 	if (code != 0) {
@@ -423,7 +425,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
 	 */
 	if (with_pac && generate_pac) {
 		DBG_DEBUG("Generate PAC for AS-REQ [%s]\n", client_name);
-		code = ks_get_pac(context, client_entry, client_key, &pac);
+		code = ks_get_pac(context, client_entry, server, client_key, &pac);
 		if (code != 0) {
 			goto done;
 		}
@@ -474,6 +476,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
 
 				code = ks_get_pac(context,
 						  client_entry,
+						  server,
 						  client_key,
 						  &pac);
 				if (code != 0 && code != ENOENT) {
diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 53c137de2fd..ef4e8c2ed38 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -433,6 +433,7 @@ int mit_samba_get_nextkey(struct mit_samba_context *ctx,
 int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 		      krb5_context context,
 		      krb5_db_entry *client,
+		      krb5_db_entry *server,
 		      krb5_keyblock *client_key,
 		      krb5_pac *pac)
 {
@@ -443,9 +444,12 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 	DATA_BLOB **cred_ndr_ptr = NULL;
 	DATA_BLOB cred_blob = data_blob_null;
 	DATA_BLOB *pcred_blob = NULL;
+	DATA_BLOB *pac_attrs_blob = NULL;
+	DATA_BLOB *requester_sid_blob = NULL;
 	NTSTATUS nt_status;
 	krb5_error_code code;
 	struct samba_kdc_entry *skdc_entry;
+	bool is_krbtgt;
 
 	skdc_entry = talloc_get_type_abort(client->e_data,
 					   struct samba_kdc_entry);
@@ -464,12 +468,16 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 	}
 #endif
 
+	is_krbtgt = ks_is_tgs_principal(smb_ctx, server->princ);
+
 	nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
 					    skdc_entry,
 					    &logon_info_blob,
 					    cred_ndr_ptr,
 					    &upn_dns_info_blob,
-					    NULL, NULL, NULL,
+					    is_krbtgt ? &pac_attrs_blob : NULL,
+					    NULL,
+					    is_krbtgt ? &requester_sid_blob : NULL,
 					    NULL);
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		talloc_free(tmp_ctx);
@@ -497,8 +505,8 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 				   logon_info_blob,
 				   pcred_blob,
 				   upn_dns_info_blob,
-				   NULL,
-				   NULL,
+				   pac_attrs_blob,
+				   requester_sid_blob,
 				   NULL,
 				   pac);
 
@@ -522,6 +530,7 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 	DATA_BLOB *pac_blob = NULL;
 	DATA_BLOB *upn_blob = NULL;
 	DATA_BLOB *deleg_blob = NULL;
+	DATA_BLOB *requester_sid_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;
@@ -537,8 +546,12 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 	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;
+	ssize_t attrs_info_idx = -1;
+	ssize_t requester_sid_idx = -1;
 	krb5_pac new_pac = NULL;
 	bool ok;
+	bool is_krbtgt;
 
 	/* Create a memory context early so code can use talloc_stackframe() */
 	tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
@@ -546,6 +559,8 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 		return ENOMEM;
 	}
 
+	is_krbtgt = ks_is_tgs_principal(ctx, server->princ);
+
 	if (client != NULL) {
 		client_skdc_entry =
 			talloc_get_type_abort(client->e_data,
@@ -604,7 +619,7 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 						    NULL,
 						    &upn_blob,
 						    NULL, NULL,
-						    NULL,
+						    &requester_sid_blob,
 						    NULL);
 		if (!NT_STATUS_IS_OK(nt_status)) {
 			code = EINVAL;
@@ -763,6 +778,45 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 			}
 			kdc_checksum_idx = i;
 			break;
+		case PAC_TYPE_TICKET_CHECKSUM:
+			if (tkt_checksum_idx != -1) {
+				DBG_WARNING("ticket checksum type[%u] twice "
+					    "[%zd] and [%zu]: \n",
+					    types[i],
+					    tkt_checksum_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			tkt_checksum_idx = i;
+			break;
+		case PAC_TYPE_ATTRIBUTES_INFO:
+			if (attrs_info_idx != -1) {
+				DBG_WARNING("attributes info type[%u] twice "
+					    "[%zd] and [%zu]: \n",
+					    types[i],
+					    attrs_info_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			attrs_info_idx = i;
+			break;
+		case PAC_TYPE_REQUESTER_SID:
+			if (requester_sid_idx != -1) {
+				DBG_WARNING("requester sid type[%u] twice"
+					    "[%zd] and [%zu]: \n",
+					    types[i],
+					    requester_sid_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			requester_sid_idx = i;
+			break;
 		default:
 			continue;
 		}
@@ -792,6 +846,13 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 		code = EINVAL;
 		goto done;
 	}
+	if (!(flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) &&
+	    requester_sid_idx == -1) {
+		DEBUG(1, ("PAC_TYPE_REQUESTER_SID missing\n"));
+		SAFE_FREE(types);
+		code = KRB5KDC_ERR_TGT_REVOKED;
+		goto done;
+	}
 
 	/* Build an updated PAC */
 	code = krb5_pac_init(context, &new_pac);
@@ -857,6 +918,10 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 			}
 			break;
 		case PAC_TYPE_SRV_CHECKSUM:
+			if (requester_sid_idx == -1 && requester_sid_blob != NULL) {
+				/* inject REQUESTER_SID */
+				forced_next_type = PAC_TYPE_REQUESTER_SID;
+			}
 			/*
 			 * This is generated in the main KDC code
 			 */
@@ -866,6 +931,26 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
 			 * This is generated in the main KDC code
 			 */
 			continue;
+		case PAC_TYPE_ATTRIBUTES_INFO:
+			if (!is_untrusted && is_krbtgt) {
+				/* just copy... */
+				break;
+			}
+
+			continue;
+		case PAC_TYPE_REQUESTER_SID:
+			if (!is_krbtgt) {
+				continue;
+			}
+
+			/*
+			 * Replace in the RODC case, otherwise
+			 * requester_sid_blob is NULL and we just copy.
+			 */
+			if (requester_sid_blob != NULL) {
+				type_blob = *requester_sid_blob;
+			}
+			break;
 		default:
 			/* just copy... */
 			break;
diff --git a/source4/kdc/mit_samba.h b/source4/kdc/mit_samba.h
index 636c77ec97c..4431e82a1b2 100644
--- a/source4/kdc/mit_samba.h
+++ b/source4/kdc/mit_samba.h
@@ -50,6 +50,7 @@ int mit_samba_get_nextkey(struct mit_samba_context *ctx,
 int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 		      krb5_context context,
 		      krb5_db_entry *client,
+		      krb5_db_entry *server,
 		      krb5_keyblock *client_key,
 		      krb5_pac *pac);
 
-- 
2.25.1


From 6199a0763507ae96aad8d6b6dff50245d505404d Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 16 Jun 2022 10:33:29 +1200
Subject: [PATCH 56/99] heimdal:kdc: Accommodate NULL data parameter in
 krb5_pac_get_buffer()

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
---
 source4/heimdal/lib/krb5/pac.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c
index 05bcc523080..100de904662 100644
--- a/source4/heimdal/lib/krb5/pac.c
+++ b/source4/heimdal/lib/krb5/pac.c
@@ -394,10 +394,12 @@ krb5_pac_get_buffer(krb5_context context, krb5_pac p,
 	if (p->pac->buffers[i].type != type)
 	    continue;
 
-	ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
-	if (ret) {
-	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
-	    return ret;
+	if (data) {
+	    ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
+	    if (ret) {
+		krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+		return ret;
+	    }
 	}
 	return 0;
     }
-- 
2.25.1


From b0d3fd37a8884cf18f9c2bffc416035747d49977 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 27 May 2022 19:17:02 +1200
Subject: [PATCH 57/99] CVE-2022-2031 s4:kpasswd: Account for missing target
 principal

This field is supposed to be optional.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/kdc/kpasswd-service-mit.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/source4/kdc/kpasswd-service-mit.c b/source4/kdc/kpasswd-service-mit.c
index 2117c1c1696..b53c1a4618a 100644
--- a/source4/kdc/kpasswd-service-mit.c
+++ b/source4/kdc/kpasswd-service-mit.c
@@ -143,16 +143,18 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 		return KRB5_KPASSWD_HARDERROR;
 	}
 
-	target_realm = smb_krb5_principal_get_realm(
-		mem_ctx, context, target_principal);
-	code = krb5_unparse_name_flags(context,
-				       target_principal,
-				       KRB5_PRINCIPAL_UNPARSE_NO_REALM,
-				       &target_name);
-	if (code != 0) {
-		DBG_WARNING("Failed to parse principal\n");
-		*error_string = "String conversion failed";
-		return KRB5_KPASSWD_HARDERROR;
+	if (target_principal != NULL) {
+		target_realm = smb_krb5_principal_get_realm(
+			mem_ctx, context, target_principal);
+		code = krb5_unparse_name_flags(context,
+					       target_principal,
+					       KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+					       &target_name);
+		if (code != 0) {
+			DBG_WARNING("Failed to parse principal\n");
+			*error_string = "String conversion failed";
+			return KRB5_KPASSWD_HARDERROR;
+		}
 	}
 
 	if ((target_name != NULL && target_realm == NULL) ||
-- 
2.25.1


From e21702d20b6d4507708791c5a6a674b8bdadaab0 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Mon, 30 May 2022 19:17:41 +1200
Subject: [PATCH 58/99] CVE-2022-2031 s4:kpasswd: Add MIT fallback for decoding
 setpw structure

The target principal and realm fields of the setpw structure are
supposed to be optional, but in MIT Kerberos they are mandatory. For
better compatibility and ease of testing, fall back to parsing the
simpler (containing only the new password) structure if the MIT function
fails to decode it.

Although the target principal and realm fields should be optional, one
is not supposed to specified without the other, so we don't have to deal
with the case where only one is specified.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/kdc/kpasswd-service-mit.c | 94 ++++++++++++++++++++++++++-----
 1 file changed, 79 insertions(+), 15 deletions(-)

diff --git a/source4/kdc/kpasswd-service-mit.c b/source4/kdc/kpasswd-service-mit.c
index b53c1a4618a..9c4d2801669 100644
--- a/source4/kdc/kpasswd-service-mit.c
+++ b/source4/kdc/kpasswd-service-mit.c
@@ -28,6 +28,7 @@
 #include "kdc/kpasswd_glue.h"
 #include "kdc/kpasswd-service.h"
 #include "kdc/kpasswd-helper.h"
+#include "../lib/util/asn1.h"
 
 #define RFC3244_VERSION 0xff80
 
@@ -35,6 +36,52 @@ krb5_error_code decode_krb5_setpw_req(const krb5_data *code,
 				      krb5_data **password_out,
 				      krb5_principal *target_out);
 
+/*
+ * A fallback for when MIT refuses to parse a setpw structure without the
+ * (optional) target principal and realm
+ */
+static bool decode_krb5_setpw_req_simple(TALLOC_CTX *mem_ctx,
+					 const DATA_BLOB *decoded_data,
+					 DATA_BLOB *clear_data)
+{
+	struct asn1_data *asn1 = NULL;
+	bool ret;
+
+	asn1 = asn1_init(mem_ctx, 3);
+	if (asn1 == NULL) {
+		return false;
+	}
+
+	ret = asn1_load(asn1, *decoded_data);
+	if (!ret) {
+		goto out;
+	}
+
+	ret = asn1_start_tag(asn1, ASN1_SEQUENCE(0));
+	if (!ret) {
+		goto out;
+	}
+	ret = asn1_start_tag(asn1, ASN1_CONTEXT(0));
+	if (!ret) {
+		goto out;
+	}
+	ret = asn1_read_OctetString(asn1, mem_ctx, clear_data);
+	if (!ret) {
+		goto out;
+	}
+
+	ret = asn1_end_tag(asn1);
+	if (!ret) {
+		goto out;
+	}
+	ret = asn1_end_tag(asn1);
+
+out:
+	asn1_free(asn1);
+
+	return ret;
+}
+
 static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
 					       TALLOC_CTX *mem_ctx,
 					       struct auth_session_info *session_info,
@@ -93,9 +140,10 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 					    const char **error_string)
 {
 	krb5_context context = kdc->smb_krb5_context->krb5_context;
+	DATA_BLOB clear_data;
 	krb5_data k_dec_data;
-	krb5_data *k_clear_data;
-	krb5_principal target_principal;
+	krb5_data *k_clear_data = NULL;
+	krb5_principal target_principal = NULL;
 	krb5_error_code code;
 	DATA_BLOB password;
 	char *target_realm = NULL;
@@ -114,29 +162,45 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 	code = decode_krb5_setpw_req(&k_dec_data,
 				     &k_clear_data,
 				     &target_principal);
-	if (code != 0) {
-		DBG_WARNING("decode_krb5_setpw_req failed: %s\n",
-			    error_message(code));
-		ok = kpasswd_make_error_reply(mem_ctx,
-					      KRB5_KPASSWD_MALFORMED,
-					      "Failed to decode packet",
-					      kpasswd_reply);
+	if (code == 0) {
+		clear_data.data = (uint8_t *)k_clear_data->data;
+		clear_data.length = k_clear_data->length;
+	} else {
+		target_principal = NULL;
+
+		/*
+		 * The MIT decode failed, so fall back to trying the simple
+		 * case, without target_principal.
+		 */
+		ok = decode_krb5_setpw_req_simple(mem_ctx,
+						  decoded_data,
+						  &clear_data);
 		if (!ok) {
-			*error_string = "Failed to create reply";
-			return KRB5_KPASSWD_HARDERROR;
+			DBG_WARNING("decode_krb5_setpw_req failed: %s\n",
+				    error_message(code));
+			ok = kpasswd_make_error_reply(mem_ctx,
+						      KRB5_KPASSWD_MALFORMED,
+						      "Failed to decode packet",
+						      kpasswd_reply);
+			if (!ok) {
+				*error_string = "Failed to create reply";
+				return KRB5_KPASSWD_HARDERROR;
+			}
+			return 0;
 		}
-		return 0;
 	}
 
 	ok = convert_string_talloc_handle(mem_ctx,
 					  lpcfg_iconv_handle(kdc->task->lp_ctx),
 					  CH_UTF8,
 					  CH_UTF16,
-					  (const char *)k_clear_data->data,
-					  k_clear_data->length,
+					  clear_data.data,
+					  clear_data.length,
 					  (void **)&password.data,
 					  &password.length);
-	krb5_free_data(context, k_clear_data);
+	if (k_clear_data != NULL) {
+		krb5_free_data(context, k_clear_data);
+	}
 	if (!ok) {
 		DBG_WARNING("String conversion failed\n");
 		*error_string = "String conversion failed";
-- 
2.25.1


From f4ea2a80d8440c4c7261229bd9285bce97226094 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 26 May 2022 16:34:01 +1200
Subject: [PATCH 59/99] CVE-2022-32744 tests/krb5: Correctly handle specifying
 account kvno

The environment variable is a string, but we expect an integer.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 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 a2241707d44..4120edf93b9 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -724,7 +724,7 @@ class RawKerberosTest(TestCaseInTempDir):
                                 fallback_default=False,
                                 allow_missing=kvno_allow_missing)
         if kvno is not None:
-            c.set_kvno(kvno)
+            c.set_kvno(int(kvno))
         aes256_key = self.env_get_var('AES256_KEY_HEX', prefix,
                                       fallback_default=False,
                                       allow_missing=aes256_allow_missing)
-- 
2.25.1


From 440aa37cc462ac9a230636e6758152c3a520fed4 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 26 May 2022 20:52:04 +1200
Subject: [PATCH 60/99] CVE-2022-2031 tests/krb5: Split out _make_tgs_request()

This allows us to make use of it in other tests.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed conflicts due to having older version of
 _make_tgs_request()]
---
 python/samba/tests/krb5/kdc_base_test.py | 77 ++++++++++++++++++++++++
 python/samba/tests/krb5/kdc_tgs_tests.py | 76 -----------------------
 2 files changed, 77 insertions(+), 76 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 58b87eab25b..2117663b26b 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -67,6 +67,7 @@ from samba.tests.krb5.rfc4120_constants import (
     AES256_CTS_HMAC_SHA1_96,
     ARCFOUR_HMAC_MD5,
     KDC_ERR_PREAUTH_REQUIRED,
+    KDC_ERR_TGT_REVOKED,
     KRB_AS_REP,
     KRB_TGS_REP,
     KRB_ERROR,
@@ -1538,6 +1539,82 @@ class KDCBaseTest(RawKerberosTest):
 
         return ticket_creds
 
+    def _make_tgs_request(self, client_creds, service_creds, tgt,
+                          pac_request=None, expect_pac=True,
+                          expect_error=False,
+                          expected_account_name=None,
+                          expected_upn_name=None,
+                          expected_sid=None):
+        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)
+
+        if expect_error:
+            expected_error_mode = KDC_ERR_TGT_REVOKED
+            check_error_fn = self.generic_check_kdc_error
+            check_rep_fn = None
+        else:
+            expected_error_mode = 0
+            check_error_fn = None
+            check_rep_fn = self.generic_check_kdc_rep
+
+        kdc_exchange_dict = self.tgs_exchange_dict(
+            expected_crealm=expected_crealm,
+            expected_cname=expected_cname,
+            expected_srealm=expected_srealm,
+            expected_sname=expected_sname,
+            expected_account_name=expected_account_name,
+            expected_upn_name=expected_upn_name,
+            expected_sid=expected_sid,
+            expected_supported_etypes=expected_supported_etypes,
+            ticket_decryption_key=target_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,
+            tgt=tgt,
+            authenticator_subkey=authenticator_subkey,
+            kdc_options=kdc_options,
+            pac_request=pac_request,
+            expect_pac=expect_pac,
+            expect_edata=False)
+
+        rep = self._generic_kdc_exchange(kdc_exchange_dict,
+                                         cname=cname,
+                                         realm=realm,
+                                         sname=sname,
+                                         etypes=etypes)
+        if expect_error:
+            self.check_error_rep(rep, expected_error_mode)
+
+            return None
+        else:
+            self.check_reply(rep, KRB_TGS_REP)
+
+            return kdc_exchange_dict['rep_ticket_creds']
+
     # Named tuple to contain values of interest when the PAC is decoded.
     PacData = namedtuple(
         "PacData",
diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 8cd27dec2aa..e52f46152fa 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -230,82 +230,6 @@ class KdcTgsTests(KDCBaseTest):
             pac_data.account_sid,
             "rep = {%s},%s" % (rep, pac_data))
 
-    def _make_tgs_request(self, client_creds, service_creds, tgt,
-                          pac_request=None, expect_pac=True,
-                          expect_error=False,
-                          expected_account_name=None,
-                          expected_upn_name=None,
-                          expected_sid=None):
-        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)
-
-        if expect_error:
-            expected_error_mode = KDC_ERR_TGT_REVOKED
-            check_error_fn = self.generic_check_kdc_error
-            check_rep_fn = None
-        else:
-            expected_error_mode = 0
-            check_error_fn = None
-            check_rep_fn = self.generic_check_kdc_rep
-
-        kdc_exchange_dict = self.tgs_exchange_dict(
-            expected_crealm=expected_crealm,
-            expected_cname=expected_cname,
-            expected_srealm=expected_srealm,
-            expected_sname=expected_sname,
-            expected_account_name=expected_account_name,
-            expected_upn_name=expected_upn_name,
-            expected_sid=expected_sid,
-            expected_supported_etypes=expected_supported_etypes,
-            ticket_decryption_key=target_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,
-            tgt=tgt,
-            authenticator_subkey=authenticator_subkey,
-            kdc_options=kdc_options,
-            pac_request=pac_request,
-            expect_pac=expect_pac,
-            expect_edata=False)
-
-        rep = self._generic_kdc_exchange(kdc_exchange_dict,
-                                         cname=cname,
-                                         realm=realm,
-                                         sname=sname,
-                                         etypes=etypes)
-        if expect_error:
-            self.check_error_rep(rep, expected_error_mode)
-
-            return None
-        else:
-            self.check_reply(rep, KRB_TGS_REP)
-
-            return kdc_exchange_dict['rep_ticket_creds']
-
     def test_request(self):
         client_creds = self.get_client_creds()
         service_creds = self.get_service_creds()
-- 
2.25.1


From efb69ab420f2c5a3074fff6192fbc9a1cd387870 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:06:53 +1200
Subject: [PATCH 61/99] CVE-2022-32744 tests/krb5: Correctly calculate salt for
 pre-existing accounts

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 python/samba/tests/krb5/kdc_base_test.py | 1 +
 python/samba/tests/krb5/raw_testcase.py  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 2117663b26b..685a6f71f88 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -1048,6 +1048,7 @@ class KDCBaseTest(RawKerberosTest):
 
             kvno = int(res[0]['msDS-KeyVersionNumber'][0])
             creds.set_kvno(kvno)
+            creds.set_workstation(username[:-1])
             creds.set_dn(dn)
 
             keys = self.get_keys(samdb, dn)
diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index 4120edf93b9..a9a98c36cbf 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -834,6 +834,7 @@ class RawKerberosTest(TestCaseInTempDir):
                                  allow_missing_password=allow_missing_password,
                                  allow_missing_keys=allow_missing_keys)
         c.set_gensec_features(c.get_gensec_features() | FEATURE_SEAL)
+        c.set_workstation('')
         return c
 
     def get_rodc_krbtgt_creds(self,
-- 
2.25.1


From 3bbb7bc57f0de9dfe8fa979b7e122cafc4f9c139 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:13:54 +1200
Subject: [PATCH 62/99] CVE-2022-2031 tests/krb5: Add new definitions for
 kpasswd

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 python/samba/tests/krb5/rfc4120.asn1         |  6 ++++++
 python/samba/tests/krb5/rfc4120_constants.py | 13 +++++++++++++
 python/samba/tests/krb5/rfc4120_pyasn1.py    | 13 ++++++++++++-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/python/samba/tests/krb5/rfc4120.asn1 b/python/samba/tests/krb5/rfc4120.asn1
index e0831e1f86f..cac884be985 100644
--- a/python/samba/tests/krb5/rfc4120.asn1
+++ b/python/samba/tests/krb5/rfc4120.asn1
@@ -567,6 +567,12 @@ PA-FX-FAST-REPLY ::= CHOICE {
         ...
 }
 
+ChangePasswdDataMS ::= SEQUENCE {
+        newpasswd       [0] OCTET STRING,
+        targname        [1] PrincipalName OPTIONAL,
+        targrealm       [2] Realm OPTIONAL
+}
+
 -- MS-KILE End
 --
 --
diff --git a/python/samba/tests/krb5/rfc4120_constants.py b/python/samba/tests/krb5/rfc4120_constants.py
index a9fdc5735dd..7f0f44500c7 100644
--- a/python/samba/tests/krb5/rfc4120_constants.py
+++ b/python/samba/tests/krb5/rfc4120_constants.py
@@ -27,11 +27,13 @@ ARCFOUR_HMAC_MD5 = int(
 
 # Message types
 KRB_ERROR = int(krb5_asn1.MessageTypeValues('krb-error'))
+KRB_AP_REP = int(krb5_asn1.MessageTypeValues('krb-ap-rep'))
 KRB_AP_REQ = int(krb5_asn1.MessageTypeValues('krb-ap-req'))
 KRB_AS_REP = int(krb5_asn1.MessageTypeValues('krb-as-rep'))
 KRB_AS_REQ = int(krb5_asn1.MessageTypeValues('krb-as-req'))
 KRB_TGS_REP = int(krb5_asn1.MessageTypeValues('krb-tgs-rep'))
 KRB_TGS_REQ = int(krb5_asn1.MessageTypeValues('krb-tgs-req'))
+KRB_PRIV = int(krb5_asn1.MessageTypeValues('krb-priv'))
 
 # PAData types
 PADATA_ENC_TIMESTAMP = int(
@@ -76,6 +78,7 @@ KDC_ERR_TGT_REVOKED = 20
 KDC_ERR_PREAUTH_FAILED = 24
 KDC_ERR_PREAUTH_REQUIRED = 25
 KDC_ERR_BAD_INTEGRITY = 31
+KDC_ERR_TKT_EXPIRED = 32
 KRB_ERR_TKT_NYV = 33
 KDC_ERR_NOT_US = 35
 KDC_ERR_BADMATCH = 36
@@ -87,6 +90,16 @@ KDC_ERR_WRONG_REALM = 68
 KDC_ERR_CLIENT_NAME_MISMATCH = 75
 KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS = 93
 
+# Kpasswd error codes
+KPASSWD_SUCCESS = 0
+KPASSWD_MALFORMED = 1
+KPASSWD_HARDERROR = 2
+KPASSWD_AUTHERROR = 3
+KPASSWD_SOFTERROR = 4
+KPASSWD_ACCESSDENIED = 5
+KPASSWD_BAD_VERSION = 6
+KPASSWD_INITIAL_FLAG_NEEDED = 7
+
 # Extended error types
 KERB_AP_ERR_TYPE_SKEW_RECOVERY = int(
     krb5_asn1.KerbErrorDataTypeValues('kERB-AP-ERR-TYPE-SKEW-RECOVERY'))
diff --git a/python/samba/tests/krb5/rfc4120_pyasn1.py b/python/samba/tests/krb5/rfc4120_pyasn1.py
index 348dd8c63fb..3c02b0efbc1 100644
--- a/python/samba/tests/krb5/rfc4120_pyasn1.py
+++ b/python/samba/tests/krb5/rfc4120_pyasn1.py
@@ -1,5 +1,5 @@
 # Auto-generated by asn1ate v.0.6.1.dev0 from rfc4120.asn1
-# (last modified on 2021-06-25 12:10:34.484667)
+# (last modified on 2022-05-13 20:03:06.039817)
 
 # KerberosV5Spec2
 from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful
@@ -364,6 +364,17 @@ Authenticator.componentType = namedtype.NamedTypes(
 )
 
 
+class ChangePasswdDataMS(univ.Sequence):
+    pass
+
+
+ChangePasswdDataMS.componentType = namedtype.NamedTypes(
+    namedtype.NamedType('newpasswd', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+    namedtype.OptionalNamedType('targname', PrincipalName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
+    namedtype.OptionalNamedType('targrealm', Realm().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
+)
+
+
 class ChecksumTypeValues(univ.Integer):
     pass
 
-- 
2.25.1


From 39db18962f5368957293cf678e4e7249a8b81ca8 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:17:45 +1200
Subject: [PATCH 63/99] CVE-2022-2031 tests/krb5: Add methods to create ASN1
 kpasswd structures

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 python/samba/tests/krb5/raw_testcase.py | 95 +++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index a9a98c36cbf..df41dff688d 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -54,6 +54,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KRB_AS_REP,
     KRB_AS_REQ,
     KRB_ERROR,
+    KRB_PRIV,
     KRB_TGS_REP,
     KRB_TGS_REQ,
     KU_AP_REQ_AUTH,
@@ -63,6 +64,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KU_FAST_FINISHED,
     KU_FAST_REP,
     KU_FAST_REQ_CHKSUM,
+    KU_KRB_PRIV,
     KU_NON_KERB_CKSUM_SALT,
     KU_TGS_REP_ENC_PART_SESSION,
     KU_TGS_REP_ENC_PART_SUB_KEY,
@@ -1780,6 +1782,99 @@ class RawKerberosTest(TestCaseInTempDir):
             PA_S4U2Self_obj, asn1Spec=krb5_asn1.PA_S4U2Self())
         return self.PA_DATA_create(PADATA_FOR_USER, pa_s4u2self)
 
+    def ChangePasswdDataMS_create(self,
+                                  new_password,
+                                  target_princ=None,
+                                  target_realm=None):
+        ChangePasswdDataMS_obj = {
+            'newpasswd': new_password,
+        }
+        if target_princ is not None:
+            ChangePasswdDataMS_obj['targname'] = target_princ
+        if target_realm is not None:
+            ChangePasswdDataMS_obj['targrealm'] = target_realm
+
+        change_password_data = self.der_encode(
+            ChangePasswdDataMS_obj, asn1Spec=krb5_asn1.ChangePasswdDataMS())
+
+        return change_password_data
+
+    def KRB_PRIV_create(self,
+                        subkey,
+                        user_data,
+                        s_address,
+                        timestamp=None,
+                        usec=None,
+                        seq_number=None,
+                        r_address=None):
+        EncKrbPrivPart_obj = {
+            'user-data': user_data,
+            's-address': s_address,
+        }
+        if timestamp is not None:
+            EncKrbPrivPart_obj['timestamp'] = timestamp
+        if usec is not None:
+            EncKrbPrivPart_obj['usec'] = usec
+        if seq_number is not None:
+            EncKrbPrivPart_obj['seq-number'] = seq_number
+        if r_address is not None:
+            EncKrbPrivPart_obj['r-address'] = r_address
+
+        enc_krb_priv_part = self.der_encode(
+            EncKrbPrivPart_obj, asn1Spec=krb5_asn1.EncKrbPrivPart())
+
+        enc_data = self.EncryptedData_create(subkey,
+                                             KU_KRB_PRIV,
+                                             enc_krb_priv_part)
+
+        KRB_PRIV_obj = {
+            'pvno': 5,
+            'msg-type': KRB_PRIV,
+            'enc-part': enc_data,
+        }
+
+        krb_priv = self.der_encode(
+            KRB_PRIV_obj, asn1Spec=krb5_asn1.KRB_PRIV())
+
+        return krb_priv
+
+    def kpasswd_create(self,
+                       subkey,
+                       user_data,
+                       version,
+                       seq_number,
+                       ap_req,
+                       local_address,
+                       remote_address):
+        self.assertIsNotNone(self.s, 'call self.connect() first')
+
+        timestamp, usec = self.get_KerberosTimeWithUsec()
+
+        krb_priv = self.KRB_PRIV_create(subkey,
+                                        user_data,
+                                        s_address=local_address,
+                                        timestamp=timestamp,
+                                        usec=usec,
+                                        seq_number=seq_number,
+                                        r_address=remote_address)
+
+        size = 6 + len(ap_req) + len(krb_priv)
+        self.assertLess(size, 0x10000)
+
+        msg = bytearray()
+        msg.append(size >> 8)
+        msg.append(size & 0xff)
+        msg.append(version >> 8)
+        msg.append(version & 0xff)
+        msg.append(len(ap_req) >> 8)
+        msg.append(len(ap_req) & 0xff)
+        # Note: for sets, there could be a little-endian four-byte length here.
+
+        msg.extend(ap_req)
+        msg.extend(krb_priv)
+
+        return msg
+
     def _generic_kdc_exchange(self,
                               kdc_exchange_dict,  # required
                               cname=None,  # optional
-- 
2.25.1


From 3852adddff6df4d9f6f4cc1add11b06c272d29ef Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:21:37 +1200
Subject: [PATCH 64/99] CVE-2022-2031 tests/krb5: Add 'port' parameter to
 connect()

This allows us to use the kpasswd port, 464.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 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 df41dff688d..421143781ae 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -638,10 +638,11 @@ class RawKerberosTest(TestCaseInTempDir):
         if self.do_hexdump:
             sys.stderr.write("disconnect[%s]\n" % reason)
 
-    def _connect_tcp(self, host):
-        tcp_port = 88
+    def _connect_tcp(self, host, port=None):
+        if port is None:
+            port = 88
         try:
-            self.a = socket.getaddrinfo(host, tcp_port, socket.AF_UNSPEC,
+            self.a = socket.getaddrinfo(host, 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])
@@ -654,9 +655,9 @@ class RawKerberosTest(TestCaseInTempDir):
             self.s.close()
             raise
 
-    def connect(self, host):
+    def connect(self, host, port=None):
         self.assertNotConnected()
-        self._connect_tcp(host)
+        self._connect_tcp(host, port)
         if self.do_hexdump:
             sys.stderr.write("connected[%s]\n" % host)
 
-- 
2.25.1


From b9e880b3d9cf5666947cae60adc0846385b04f54 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:20:28 +1200
Subject: [PATCH 65/99] CVE-2022-2031 tests/krb5: Add methods to send and
 receive generic messages

This allows us to send and receive kpasswd messages, while avoiding the
existing logic for encoding and decoding other Kerberos message types.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 python/samba/tests/krb5/raw_testcase.py | 44 +++++++++++++++----------
 1 file changed, 27 insertions(+), 17 deletions(-)

diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index 421143781ae..2aed5530455 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -920,24 +920,28 @@ class RawKerberosTest(TestCaseInTempDir):
         return blob
 
     def send_pdu(self, req, asn1_print=None, hexdump=None):
+        k5_pdu = self.der_encode(
+            req, native_decode=False, asn1_print=asn1_print, hexdump=False)
+        self.send_msg(k5_pdu, hexdump=hexdump)
+
+    def send_msg(self, msg, hexdump=None):
+        header = struct.pack('>I', len(msg))
+        req_pdu = header
+        req_pdu += msg
+        self.hex_dump("send_msg", header, hexdump=hexdump)
+        self.hex_dump("send_msg", msg, hexdump=hexdump)
+
         try:
-            k5_pdu = self.der_encode(
-                req, native_decode=False, asn1_print=asn1_print, hexdump=False)
-            header = struct.pack('>I', len(k5_pdu))
-            req_pdu = header
-            req_pdu += k5_pdu
-            self.hex_dump("send_pdu", header, hexdump=hexdump)
-            self.hex_dump("send_pdu", k5_pdu, hexdump=hexdump)
             while True:
                 sent = self.s.send(req_pdu, 0)
                 if sent == len(req_pdu):
-                    break
+                    return
                 req_pdu = req_pdu[sent:]
         except socket.error as e:
-            self._disconnect("send_pdu: %s" % e)
+            self._disconnect("send_msg: %s" % e)
             raise
         except IOError as e:
-            self._disconnect("send_pdu: %s" % e)
+            self._disconnect("send_msg: %s" % e)
             raise
 
     def recv_raw(self, num_recv=0xffff, hexdump=None, timeout=None):
@@ -963,16 +967,14 @@ class RawKerberosTest(TestCaseInTempDir):
         return rep_pdu
 
     def recv_pdu_raw(self, asn1_print=None, hexdump=None, timeout=None):
-        rep_pdu = None
-        rep = None
         raw_pdu = self.recv_raw(
             num_recv=4, hexdump=hexdump, timeout=timeout)
         if raw_pdu is None:
-            return (None, None)
+            return None
         header = struct.unpack(">I", raw_pdu[0:4])
         k5_len = header[0]
         if k5_len == 0:
-            return (None, "")
+            return ""
         missing = k5_len
         rep_pdu = b''
         while missing > 0:
@@ -981,6 +983,14 @@ class RawKerberosTest(TestCaseInTempDir):
             self.assertGreaterEqual(len(raw_pdu), 1)
             rep_pdu += raw_pdu
             missing = k5_len - len(rep_pdu)
+        return rep_pdu
+
+    def recv_reply(self, asn1_print=None, hexdump=None, timeout=None):
+        rep_pdu = self.recv_pdu_raw(asn1_print=asn1_print,
+                                    hexdump=hexdump,
+                                    timeout=timeout)
+        if not rep_pdu:
+            return None, rep_pdu
         k5_raw = self.der_decode(
             rep_pdu,
             asn1Spec=None,
@@ -1002,9 +1012,9 @@ class RawKerberosTest(TestCaseInTempDir):
         return (rep, rep_pdu)
 
     def recv_pdu(self, asn1_print=None, hexdump=None, timeout=None):
-        (rep, rep_pdu) = self.recv_pdu_raw(asn1_print=asn1_print,
-                                           hexdump=hexdump,
-                                           timeout=timeout)
+        (rep, rep_pdu) = self.recv_reply(asn1_print=asn1_print,
+                                         hexdump=hexdump,
+                                         timeout=timeout)
         return rep
 
     def assertIsConnected(self):
-- 
2.25.1


From 57edd8e2e043bd226c91ab0791297c1d98549ff1 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:26:56 +1200
Subject: [PATCH 66/99] tests/krb5: Fix enum typo

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 python/samba/tests/krb5/kdc_base_test.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 685a6f71f88..14f1d1a243d 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -248,9 +248,9 @@ class KDCBaseTest(RawKerberosTest):
            which is used by tearDownClass to clean up the created accounts.
         '''
         if ou is None:
-            if account_type is account_type.COMPUTER:
+            if account_type is self.AccountType.COMPUTER:
                 guid = DS_GUID_COMPUTERS_CONTAINER
-            elif account_type is account_type.SERVER:
+            elif account_type is self.AccountType.SERVER:
                 guid = DS_GUID_DOMAIN_CONTROLLERS_CONTAINER
             else:
                 guid = DS_GUID_USERS_CONTAINER
-- 
2.25.1


From e44b70b862e93fb9a8139a7188ed7021d705d223 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:30:12 +1200
Subject: [PATCH 67/99] tests/krb5: Add option for creating accounts with
 expired passwords

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 python/samba/tests/krb5/kdc_base_test.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 14f1d1a243d..777b3b4aaf1 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -242,7 +242,8 @@ 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, add_dollar=True):
+                       ou=None, account_control=0, add_dollar=True,
+                       expired_password=False):
         '''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.
@@ -294,6 +295,8 @@ class KDCBaseTest(RawKerberosTest):
             details["servicePrincipalName"] = spn
         if upn is not None:
             details["userPrincipalName"] = upn
+        if expired_password:
+            details["pwdLastSet"] = "0"
         if additional_details is not None:
             details.update(additional_details)
         samdb.add(details)
@@ -653,6 +656,7 @@ class KDCBaseTest(RawKerberosTest):
             'revealed_to_rodc': False,
             'revealed_to_mock_rodc': False,
             'no_auth_data_required': False,
+            'expired_password': False,
             'supported_enctypes': None,
             'not_delegated': False,
             'delegation_to_spn': None,
@@ -695,6 +699,7 @@ class KDCBaseTest(RawKerberosTest):
                             revealed_to_rodc,
                             revealed_to_mock_rodc,
                             no_auth_data_required,
+                            expired_password,
                             supported_enctypes,
                             not_delegated,
                             delegation_to_spn,
@@ -754,7 +759,8 @@ class KDCBaseTest(RawKerberosTest):
                                         spn=spn,
                                         additional_details=details,
                                         account_control=user_account_control,
-                                        add_dollar=add_dollar)
+                                        add_dollar=add_dollar,
+                                        expired_password=expired_password)
 
         keys = self.get_keys(samdb, dn)
         self.creds_set_keys(creds, keys)
-- 
2.25.1


From 2815de0510e222bc93f5b602b2cdd5c51f8adeb4 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:34:59 +1200
Subject: [PATCH 68/99] CVE-2022-2031 tests/krb5: Allow requesting a TGT to a
 different sname and realm

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed conflict due to lacking rc4_support parameter]

[jsutton@samba.org Fixed conflicts due to lacking client_name_type and
 expected_cname parameters]
---
 python/samba/tests/krb5/kdc_base_test.py | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 777b3b4aaf1..c0ca881985a 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -1344,10 +1344,12 @@ class KDCBaseTest(RawKerberosTest):
                            expected_flags=None, unexpected_flags=None,
                            pac_request=True, expect_pac=True, fresh=False):
         user_name = tgt.cname['name-string'][0]
+        ticket_sname = tgt.sname
         if target_name is None:
             target_name = target_creds.get_username()[:-1]
         cache_key = (user_name, target_name, service, to_rodc, kdc_options,
                      pac_request, str(expected_flags), str(unexpected_flags),
+                     str(ticket_sname),
                      expect_pac)
 
         if not fresh:
@@ -1414,6 +1416,7 @@ class KDCBaseTest(RawKerberosTest):
                 expected_flags=None, unexpected_flags=None,
                 expected_account_name=None, expected_upn_name=None,
                 expected_sid=None,
+                sname=None, realm=None,
                 pac_request=True, expect_pac=True,
                 expect_pac_attrs=None, expect_pac_attrs_pac_request=None,
                 expect_requester_sid=None,
@@ -1422,6 +1425,7 @@ class KDCBaseTest(RawKerberosTest):
         cache_key = (user_name, to_rodc, kdc_options, pac_request,
                      str(expected_flags), str(unexpected_flags),
                      expected_account_name, expected_upn_name, expected_sid,
+                     str(sname), str(realm),
                      expect_pac, expect_pac_attrs,
                      expect_pac_attrs_pac_request, expect_requester_sid)
 
@@ -1431,15 +1435,21 @@ class KDCBaseTest(RawKerberosTest):
             if tgt is not None:
                 return tgt
 
-        realm = creds.get_realm()
+        if realm is None:
+            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])
+        if sname is None:
+            sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+                                              names=['krbtgt', realm])
+            expected_sname = self.PrincipalName_create(
+                name_type=NT_SRV_INST, names=['krbtgt', realm.upper()])
+        else:
+            expected_sname = sname
 
         till = self.get_KerberosTime(offset=36000)
 
@@ -1505,9 +1515,6 @@ class KDCBaseTest(RawKerberosTest):
 
         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,
-- 
2.25.1


From e56d66f729ba1713e59b2fb938cc09e69831ac0e Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:57:57 +1200
Subject: [PATCH 69/99] CVE-2022-2031 tests/krb5: Add kpasswd_exchange() method

Now we can test the kpasswd service from Python.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed conflicts in imports]
---
 python/samba/tests/krb5/raw_testcase.py | 264 ++++++++++++++++++++++--
 1 file changed, 251 insertions(+), 13 deletions(-)

diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index 2aed5530455..57010ae73bd 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -26,6 +26,8 @@ import binascii
 import itertools
 import collections
 
+from enum import Enum
+
 from pyasn1.codec.der.decoder import decode as pyasn1_der_decode
 from pyasn1.codec.der.encoder import encode as pyasn1_der_encode
 from pyasn1.codec.native.decoder import decode as pyasn1_native_decode
@@ -33,6 +35,8 @@ from pyasn1.codec.native.encoder import encode as pyasn1_native_encode
 
 from pyasn1.codec.ber.encoder import BitStringEncoder
 
+from pyasn1.error import PyAsn1Error
+
 from samba.credentials import Credentials
 from samba.dcerpc import krb5pac, security
 from samba.gensec import FEATURE_SEAL
@@ -50,6 +54,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KDC_ERR_PREAUTH_FAILED,
     KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
     KERB_ERR_TYPE_EXTENDED,
+    KRB_AP_REP,
     KRB_AP_REQ,
     KRB_AS_REP,
     KRB_AS_REQ,
@@ -59,6 +64,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KRB_TGS_REQ,
     KU_AP_REQ_AUTH,
     KU_AS_REP_ENC_PART,
+    KU_AP_REQ_ENC_PART,
     KU_ENC_CHALLENGE_KDC,
     KU_FAST_ENC,
     KU_FAST_FINISHED,
@@ -73,6 +79,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KU_TGS_REQ_AUTH_DAT_SESSION,
     KU_TGS_REQ_AUTH_DAT_SUBKEY,
     KU_TICKET,
+    NT_PRINCIPAL,
     NT_SRV_INST,
     NT_WELLKNOWN,
     PADATA_ENCRYPTED_CHALLENGE,
@@ -515,6 +522,10 @@ class KerberosTicketCreds:
 class RawKerberosTest(TestCaseInTempDir):
     """A raw Kerberos Test case."""
 
+    class KpasswdMode(Enum):
+        SET = object()
+        CHANGE = object()
+
     pac_checksum_types = {krb5pac.PAC_TYPE_SRV_CHECKSUM,
                           krb5pac.PAC_TYPE_KDC_CHECKSUM,
                           krb5pac.PAC_TYPE_TICKET_CHECKSUM}
@@ -1886,6 +1897,224 @@ class RawKerberosTest(TestCaseInTempDir):
 
         return msg
 
+    def get_enc_part(self, obj, key, usage):
+        self.assertElementEqual(obj, 'pvno', 5)
+
+        enc_part = obj['enc-part']
+        self.assertElementEqual(enc_part, 'etype', key.etype)
+        self.assertElementKVNO(enc_part, 'kvno', key.kvno)
+
+        enc_part = key.decrypt(usage, enc_part['cipher'])
+
+        return enc_part
+
+    def kpasswd_exchange(self,
+                         ticket,
+                         new_password,
+                         expected_code,
+                         expected_msg,
+                         mode,
+                         target_princ=None,
+                         target_realm=None,
+                         ap_options=None,
+                         send_seq_number=True):
+        if mode is self.KpasswdMode.SET:
+            version = 0xff80
+            user_data = self.ChangePasswdDataMS_create(new_password,
+                                                       target_princ,
+                                                       target_realm)
+        elif mode is self.KpasswdMode.CHANGE:
+            self.assertIsNone(target_princ,
+                              'target_princ only valid for pw set')
+            self.assertIsNone(target_realm,
+                              'target_realm only valid for pw set')
+
+            version = 1
+            user_data = new_password.encode('utf-8')
+        else:
+            self.fail(f'invalid mode {mode}')
+
+        subkey = self.RandomKey(kcrypto.Enctype.AES256)
+
+        if ap_options is None:
+            ap_options = '0'
+        ap_options = str(krb5_asn1.APOptions(ap_options))
+
+        kdc_exchange_dict = {
+            'tgt': ticket,
+            'authenticator_subkey': subkey,
+            'auth_data': None,
+            'ap_options': ap_options,
+        }
+
+        if send_seq_number:
+            seq_number = random.randint(0, 0xfffffffe)
+        else:
+            seq_number = None
+
+        ap_req = self.generate_ap_req(kdc_exchange_dict,
+                                      None,
+                                      req_body=None,
+                                      armor=False,
+                                      usage=KU_AP_REQ_AUTH,
+                                      seq_number=seq_number)
+
+        self.connect(self.host, port=464)
+        self.assertIsNotNone(self.s)
+
+        family = self.s.family
+
+        if family == socket.AF_INET:
+            addr_type = 2  # IPv4
+        elif family == socket.AF_INET6:
+            addr_type = 24  # IPv6
+        else:
+            self.fail(f'unknown family {family}')
+
+        def create_address(ip):
+            return {
+                'addr-type': addr_type,
+                'address': socket.inet_pton(family, ip),
+            }
+
+        local_ip = self.s.getsockname()[0]
+        local_address = create_address(local_ip)
+
+        # remote_ip = self.s.getpeername()[0]
+        # remote_address = create_address(remote_ip)
+
+        # TODO: due to a bug (?), MIT Kerberos will not accept the request
+        # unless r-address is set to our _local_ address. Heimdal, on the other
+        # hand, requires the r-address is set to the remote address (as
+        # expected). To avoid problems, avoid sending r-address for now.
+        remote_address = None
+
+        msg = self.kpasswd_create(subkey,
+                                  user_data,
+                                  version,
+                                  seq_number,
+                                  ap_req,
+                                  local_address,
+                                  remote_address)
+
+        self.send_msg(msg)
+        rep_pdu = self.recv_pdu_raw()
+
+        self._disconnect('transaction done')
+
+        self.assertIsNotNone(rep_pdu)
+
+        header = rep_pdu[:6]
+        reply = rep_pdu[6:]
+
+        reply_len = (header[0] << 8) | header[1]
+        reply_version = (header[2] << 8) | header[3]
+        ap_rep_len = (header[4] << 8) | header[5]
+
+        self.assertEqual(reply_len, len(rep_pdu))
+        self.assertEqual(1, reply_version)  # KRB5_KPASSWD_VERS_CHANGEPW
+        self.assertLess(ap_rep_len, reply_len)
+
+        self.assertNotEqual(0x7e, rep_pdu[1])
+        self.assertNotEqual(0x5e, rep_pdu[1])
+
+        if ap_rep_len:
+            # We received an AP-REQ and KRB-PRIV as a response. This may or may
+            # not indicate an error, depending on the status code.
+            ap_rep = reply[:ap_rep_len]
+            krb_priv = reply[ap_rep_len:]
+
+            key = ticket.session_key
+
+            ap_rep = self.der_decode(ap_rep, asn1Spec=krb5_asn1.AP_REP())
+            self.assertElementEqual(ap_rep, 'msg-type', KRB_AP_REP)
+            enc_part = self.get_enc_part(ap_rep, key, KU_AP_REQ_ENC_PART)
+            enc_part = self.der_decode(
+                enc_part, asn1Spec=krb5_asn1.EncAPRepPart())
+
+            self.assertElementPresent(enc_part, 'ctime')
+            self.assertElementPresent(enc_part, 'cusec')
+            # self.assertElementMissing(enc_part, 'subkey') # TODO
+            # self.assertElementPresent(enc_part, 'seq-number') # TODO
+
+            try:
+                krb_priv = self.der_decode(krb_priv, asn1Spec=krb5_asn1.KRB_PRIV())
+            except PyAsn1Error:
+                self.fail()
+
+            self.assertElementEqual(krb_priv, 'msg-type', KRB_PRIV)
+            priv_enc_part = self.get_enc_part(krb_priv, subkey, KU_KRB_PRIV)
+            priv_enc_part = self.der_decode(
+                priv_enc_part, asn1Spec=krb5_asn1.EncKrbPrivPart())
+
+            self.assertElementMissing(priv_enc_part, 'timestamp')
+            self.assertElementMissing(priv_enc_part, 'usec')
+            # self.assertElementPresent(priv_enc_part, 'seq-number') # TODO
+            # self.assertElementEqual(priv_enc_part, 's-address', remote_address) # TODO
+            # self.assertElementMissing(priv_enc_part, 'r-address') # TODO
+
+            result_data = priv_enc_part['user-data']
+        else:
+            # We received a KRB-ERROR as a response, indicating an error.
+            krb_error = self.der_decode(reply, asn1Spec=krb5_asn1.KRB_ERROR())
+
+            sname = self.PrincipalName_create(
+                name_type=NT_PRINCIPAL,
+                names=['kadmin', 'changepw'])
+            realm = self.get_krbtgt_creds().get_realm().upper()
+
+            self.assertElementEqual(krb_error, 'pvno', 5)
+            self.assertElementEqual(krb_error, 'msg-type', KRB_ERROR)
+            self.assertElementMissing(krb_error, 'ctime')
+            self.assertElementMissing(krb_error, 'usec')
+            self.assertElementPresent(krb_error, 'stime')
+            self.assertElementPresent(krb_error, 'susec')
+
+            error_code = krb_error['error-code']
+            if isinstance(expected_code, int):
+                self.assertEqual(error_code, expected_code)
+            else:
+                self.assertIn(error_code, expected_code)
+
+            self.assertElementMissing(krb_error, 'crealm')
+            self.assertElementMissing(krb_error, 'cname')
+            self.assertElementEqual(krb_error, 'realm', realm.encode('utf-8'))
+            self.assertElementEqualPrincipal(krb_error, 'sname', sname)
+            self.assertElementMissing(krb_error, 'e-text')
+
+            result_data = krb_error['e-data']
+
+        status = result_data[:2]
+        message = result_data[2:]
+
+        status_code = (status[0] << 8) | status[1]
+        if isinstance(expected_code, int):
+            self.assertEqual(status_code, expected_code)
+        else:
+            self.assertIn(status_code, expected_code)
+
+        if not message:
+            self.assertEqual(0, status_code,
+                             'got an error result, but no message')
+            return
+
+        # Check the first character of the message.
+        if message[0]:
+            if isinstance(expected_msg, bytes):
+                self.assertEqual(message, expected_msg)
+            else:
+                self.assertIn(message, expected_msg)
+        else:
+            # We got AD password policy information.
+            self.assertEqual(30, len(message))
+
+            (empty_bytes,
+             min_length,
+             history_length,
+             properties,
+             expire_time,
+             min_age) = struct.unpack('>HIIIQQ', message)
+
     def _generic_kdc_exchange(self,
                               kdc_exchange_dict,  # required
                               cname=None,  # optional
@@ -1996,7 +2225,7 @@ class RawKerberosTest(TestCaseInTempDir):
             self.assertIsNotNone(generate_fast_fn)
             fast_ap_req = generate_fast_armor_fn(kdc_exchange_dict,
                                                  callback_dict,
-                                                 req_body,
+                                                 None,
                                                  armor=True)
 
             fast_armor_type = kdc_exchange_dict['fast_armor_type']
@@ -3211,31 +3440,39 @@ class RawKerberosTest(TestCaseInTempDir):
                         kdc_exchange_dict,
                         _callback_dict,
                         req_body,
-                        armor):
+                        armor,
+                        usage=None,
+                        seq_number=None):
+        req_body_checksum = None
+
         if armor:
+            self.assertIsNone(req_body)
+
             tgt = kdc_exchange_dict['armor_tgt']
             authenticator_subkey = kdc_exchange_dict['armor_subkey']
-
-            req_body_checksum = None
         else:
             tgt = kdc_exchange_dict['tgt']
             authenticator_subkey = kdc_exchange_dict['authenticator_subkey']
-            body_checksum_type = kdc_exchange_dict['body_checksum_type']
 
-            req_body_blob = self.der_encode(req_body,
-                                            asn1Spec=krb5_asn1.KDC_REQ_BODY())
+            if req_body is not None:
+                body_checksum_type = kdc_exchange_dict['body_checksum_type']
+
+                req_body_blob = self.der_encode(
+                    req_body, asn1Spec=krb5_asn1.KDC_REQ_BODY())
 
-            req_body_checksum = self.Checksum_create(tgt.session_key,
-                                                     KU_TGS_REQ_AUTH_CKSUM,
-                                                     req_body_blob,
-                                                     ctype=body_checksum_type)
+                req_body_checksum = self.Checksum_create(
+                    tgt.session_key,
+                    KU_TGS_REQ_AUTH_CKSUM,
+                    req_body_blob,
+                    ctype=body_checksum_type)
 
         auth_data = kdc_exchange_dict['auth_data']
 
         subkey_obj = None
         if authenticator_subkey is not None:
             subkey_obj = authenticator_subkey.export_obj()
-        seq_number = random.randint(0, 0xfffffffe)
+        if seq_number is None:
+            seq_number = random.randint(0, 0xfffffffe)
         (ctime, cusec) = self.get_KerberosTimeWithUsec()
         authenticator_obj = self.Authenticator_create(
             crealm=tgt.crealm,
@@ -3250,7 +3487,8 @@ class RawKerberosTest(TestCaseInTempDir):
             authenticator_obj,
             asn1Spec=krb5_asn1.Authenticator())
 
-        usage = KU_AP_REQ_AUTH if armor else KU_TGS_REQ_AUTH
+        if usage is None:
+            usage = KU_AP_REQ_AUTH if armor else KU_TGS_REQ_AUTH
         authenticator = self.EncryptedData_create(tgt.session_key,
                                                   usage,
                                                   authenticator_blob)
-- 
2.25.1


From b2c3b060baedf638d7b8ee7f3b2bc1c7f9b695ac Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 26 May 2022 16:35:03 +1200
Subject: [PATCH 70/99] CVE-2022-32744 selftest: Specify Administrator kvno for
 Python krb5 tests

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/selftest/tests.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index dc340623f3e..c5fdf7fe294 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -912,6 +912,7 @@ krb5_environ = {
     'SERVICE_USERNAME': '$SERVER',
     'ADMIN_USERNAME': '$DC_USERNAME',
     'ADMIN_PASSWORD': '$DC_PASSWORD',
+    'ADMIN_KVNO': '1',
     'FOR_USER': '$DC_USERNAME',
     'STRICT_CHECKING':'0',
     'FAST_SUPPORT': have_fast_support,
-- 
2.25.1


From 6fc3d93b4fe81be8e8f134c46d461d5815edda91 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 19:59:16 +1200
Subject: [PATCH 71/99] CVE-2022-2031 tests/krb5: Add tests for kpasswd service

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed conflicts in usage.py and knownfails; removed
 MIT KDC 1.20-specific knownfails as it's not supported]

[jsutton@samba.org Fixed conflicts in usage.py, knownfails, and
 tests.py]
---
 python/samba/tests/krb5/kdc_base_test.py |    4 +-
 python/samba/tests/krb5/kpasswd_tests.py | 1021 ++++++++++++++++++++++
 python/samba/tests/krb5/raw_testcase.py  |    8 +
 python/samba/tests/usage.py              |    1 +
 selftest/knownfail_heimdal_kdc           |   26 +
 selftest/knownfail_mit_kdc               |   26 +
 source4/selftest/tests.py                |    4 +
 7 files changed, 1089 insertions(+), 1 deletion(-)
 create mode 100755 python/samba/tests/krb5/kpasswd_tests.py

diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index c0ca881985a..f0306dde110 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -1586,7 +1586,9 @@ class KDCBaseTest(RawKerberosTest):
         authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
 
         if expect_error:
-            expected_error_mode = KDC_ERR_TGT_REVOKED
+            expected_error_mode = expect_error
+            if expected_error_mode is True:
+                expected_error_mode = KDC_ERR_TGT_REVOKED
             check_error_fn = self.generic_check_kdc_error
             check_rep_fn = None
         else:
diff --git a/python/samba/tests/krb5/kpasswd_tests.py b/python/samba/tests/krb5/kpasswd_tests.py
new file mode 100755
index 00000000000..3a6c7d818dc
--- /dev/null
+++ b/python/samba/tests/krb5/kpasswd_tests.py
@@ -0,0 +1,1021 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) Catalyst.Net Ltd
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+import os
+import sys
+
+from functools import partial
+
+from samba import generate_random_password, unix2nttime
+from samba.dcerpc import krb5pac, security
+from samba.sd_utils import SDUtils
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.rfc4120_constants import (
+    KDC_ERR_TGT_REVOKED,
+    KDC_ERR_TKT_EXPIRED,
+    KPASSWD_ACCESSDENIED,
+    KPASSWD_HARDERROR,
+    KPASSWD_INITIAL_FLAG_NEEDED,
+    KPASSWD_MALFORMED,
+    KPASSWD_SOFTERROR,
+    KPASSWD_SUCCESS,
+    NT_PRINCIPAL,
+    NT_SRV_INST,
+)
+
+sys.path.insert(0, 'bin/python')
+os.environ['PYTHONUNBUFFERED'] = '1'
+
+global_asn1_print = False
+global_hexdump = False
+
+
+# Note: these tests do not pass on Windows, which returns different error codes
+# to the ones we have chosen, and does not always return additional error data.
+class KpasswdTests(KDCBaseTest):
+
+    def setUp(self):
+        super().setUp()
+        self.do_asn1_print = global_asn1_print
+        self.do_hexdump = global_hexdump
+
+        samdb = self.get_samdb()
+
+        # Get the old 'dSHeuristics' if it was set
+        dsheuristics = samdb.get_dsheuristics()
+
+        # Reset the 'dSHeuristics' as they were before
+        self.addCleanup(samdb.set_dsheuristics, dsheuristics)
+
+        # Set the 'dSHeuristics' to activate the correct 'userPassword'
+        # behaviour
+        samdb.set_dsheuristics('000000001')
+
+        # Get the old 'minPwdAge'
+        minPwdAge = samdb.get_minPwdAge()
+
+        # Reset the 'minPwdAge' as it was before
+        self.addCleanup(samdb.set_minPwdAge, minPwdAge)
+
+        # Set it temporarily to '0'
+        samdb.set_minPwdAge('0')
+
+    def _get_creds(self, expired=False):
+        opts = {
+            'expired_password': expired
+        }
+
+        # Create the account.
+        creds = self.get_cached_creds(account_type=self.AccountType.USER,
+                                      opts=opts,
+                                      use_cache=False)
+
+        return creds
+
+    def issued_by_rodc(self, ticket):
+        krbtgt_creds = self.get_mock_rodc_krbtgt_creds()
+
+        krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+        checksum_keys = {
+            krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key,
+        }
+
+        return self.modified_ticket(
+            ticket,
+            new_ticket_key=krbtgt_key,
+            checksum_keys=checksum_keys)
+
+    def get_kpasswd_sname(self):
+        return self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                         names=['kadmin', 'changepw'])
+
+    def get_ticket_lifetime(self, ticket):
+        enc_part = ticket.ticket_private
+
+        authtime = enc_part['authtime']
+        starttime = enc_part.get('starttime', authtime)
+        endtime = enc_part['endtime']
+
+        starttime = self.get_EpochFromKerberosTime(starttime)
+        endtime = self.get_EpochFromKerberosTime(endtime)
+
+        return endtime - starttime
+
+    def add_requester_sid(self, pac, sid):
+        pac_buffers = pac.buffers
+
+        buffer_types = [pac_buffer.type for pac_buffer in pac_buffers]
+        self.assertNotIn(krb5pac.PAC_TYPE_REQUESTER_SID, buffer_types)
+
+        requester_sid = krb5pac.PAC_REQUESTER_SID()
+        requester_sid.sid = security.dom_sid(sid)
+
+        requester_sid_buffer = krb5pac.PAC_BUFFER()
+        requester_sid_buffer.type = krb5pac.PAC_TYPE_REQUESTER_SID
+        requester_sid_buffer.info = requester_sid
+
+        pac_buffers.append(requester_sid_buffer)
+
+        pac.buffers = pac_buffers
+        pac.num_buffers += 1
+
+        return pac
+
+    # Test setting a password with kpasswd.
+    def test_kpasswd_set(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Test the newly set password.
+        creds.update_password(new_password)
+        self.get_tgt(creds, fresh=True)
+
+    # Test changing a password with kpasswd.
+    def test_kpasswd_change(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+        # Test the newly set password.
+        creds.update_password(new_password)
+        self.get_tgt(creds, fresh=True)
+
+    # Test kpasswd without setting the canonicalize option.
+    def test_kpasswd_no_canonicalize(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        sname = self.get_kpasswd_sname()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=sname,
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        creds.update_password(new_password)
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=sname,
+                              kdc_options='0')
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test kpasswd with the canonicalize option reset and a non-canonical
+    # (by conversion to title case) realm.
+    def test_kpasswd_no_canonicalize_realm_case(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        sname = self.get_kpasswd_sname()
+        realm = creds.get_realm().capitalize()  # We use a title-cased realm.
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=sname,
+                              realm=realm,
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        creds.update_password(new_password)
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=sname,
+                              realm=realm,
+                              kdc_options='0')
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test kpasswd with the canonicalize option set.
+    def test_kpasswd_canonicalize(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd. We set the canonicalize flag here.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='canonicalize')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        creds.update_password(new_password)
+
+        # Get an initial ticket to kpasswd. We set the canonicalize flag here.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='canonicalize')
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test kpasswd with the canonicalize option set and a non-canonical (by
+    # conversion to title case) realm.
+    def test_kpasswd_canonicalize_realm_case(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        sname = self.get_kpasswd_sname()
+        realm = creds.get_realm().capitalize()  # We use a title-cased realm.
+
+        # Get an initial ticket to kpasswd. We set the canonicalize flag here.
+        ticket = self.get_tgt(creds, sname=sname,
+                              realm=realm,
+                              kdc_options='canonicalize')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        creds.update_password(new_password)
+
+        # Get an initial ticket to kpasswd. We set the canonicalize flag here.
+        ticket = self.get_tgt(creds, sname=sname,
+                              realm=realm,
+                              kdc_options='canonicalize')
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test kpasswd rejects a password that does not meet complexity
+    # requirements.
+    def test_kpasswd_too_weak(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SOFTERROR
+        expected_msg = b'Password does not meet complexity requirements'
+
+        # Set the password.
+        new_password = 'password'
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test kpasswd rejects an empty new password.
+    def test_kpasswd_empty(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SOFTERROR, KPASSWD_HARDERROR
+        expected_msg = (b'Password too short, password must be at least 7 '
+                        b'characters long.',
+                        b'String conversion failed!')
+
+        # Set the password.
+        new_password = ''
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        expected_code = KPASSWD_HARDERROR
+        expected_msg = b'String conversion failed!'
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test kpasswd rejects a request that does not include a random sequence
+    # number.
+    def test_kpasswd_no_seq_number(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_HARDERROR
+        expected_msg = b'gensec_unwrap failed - NT_STATUS_ACCESS_DENIED\n'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET,
+                              send_seq_number=False)
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE,
+                              send_seq_number=False)
+
+    # Test kpasswd rejects a ticket issued by an RODC.
+    def test_kpasswd_from_rodc(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        # Have the ticket be issued by the RODC.
+        ticket = self.issued_by_rodc(ticket)
+
+        expected_code = KPASSWD_HARDERROR
+        expected_msg = b'gensec_update failed - NT_STATUS_LOGON_FAILURE\n'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test setting a password, specifying the principal of the target user.
+    def test_kpasswd_set_target_princ_only(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+        username = creds.get_username()
+
+        cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                          names=username.split('/'))
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_MALFORMED
+        expected_msg = (b'Realm and principal must be both present, or '
+                        b'neither present',
+                        b'Failed to decode packet')
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET,
+                              target_princ=cname)
+
+    # Test that kpasswd rejects a password set specifying only the realm of the
+    # target user.
+    def test_kpasswd_set_target_realm_only(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_MALFORMED, KPASSWD_ACCESSDENIED
+        expected_msg = (b'Realm and principal must be both present, or '
+                        b'neither present',
+                        b'Failed to decode packet',
+                        b'No such user when changing password')
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET,
+                              target_realm=creds.get_realm())
+
+    # Show that a user cannot set a password, specifying both principal and
+    # realm of the target user, without having control access.
+    def test_kpasswd_set_target_princ_and_realm_no_access(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+        username = creds.get_username()
+
+        cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                          names=username.split('/'))
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_ACCESSDENIED
+        expected_msg = b'Not permitted to change password'
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET,
+                              target_princ=cname,
+                              target_realm=creds.get_realm())
+
+    # Test setting a password, specifying both principal and realm of the
+    # target user, whem the user has control access on their account.
+    def test_kpasswd_set_target_princ_and_realm_access(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+        username = creds.get_username()
+        tgt = self.get_tgt(creds)
+
+        cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                          names=username.split('/'))
+
+        samdb = self.get_samdb()
+        sd_utils = SDUtils(samdb)
+
+        user_dn = creds.get_dn()
+        user_sid = self.get_objectSid(samdb, user_dn)
+
+        # Give the user control access on their account.
+        ace = f'(A;;CR;;;{user_sid})'
+        sd_utils.dacl_add_ace(user_dn, ace)
+
+        # Get a non-initial ticket to kpasswd. Since we have the right to
+        # change the account's password, we don't need an initial ticket.
+        krbtgt_creds = self.get_krbtgt_creds()
+        ticket = self.get_service_ticket(tgt,
+                                         krbtgt_creds,
+                                         service='kadmin',
+                                         target_name='changepw',
+                                         kdc_options='0')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET,
+                              target_princ=cname,
+                              target_realm=creds.get_realm())
+
+    # Test setting a password when the existing password has expired.
+    def test_kpasswd_set_expired_password(self):
+        # Create an account for testing, with an expired password.
+        creds = self._get_creds(expired=True)
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+    # Test changing a password when the existing password has expired.
+    def test_kpasswd_change_expired_password(self):
+        # Create an account for testing, with an expired password.
+        creds = self._get_creds(expired=True)
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Check the lifetime of a kpasswd ticket is not more than two minutes.
+    def test_kpasswd_ticket_lifetime(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        # Check the lifetime of the ticket is equal to two minutes.
+        lifetime = self.get_ticket_lifetime(ticket)
+        self.assertEqual(2 * 60, lifetime)
+
+    # Ensure we cannot perform a TGS-REQ with a kpasswd ticket.
+    def test_kpasswd_ticket_tgs(self):
+        creds = self.get_client_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        # Change the sname of the ticket to match that of a TGT.
+        realm = creds.get_realm()
+        krbtgt_sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+                                                 names=['krbtgt', realm])
+        ticket.set_sname(krbtgt_sname)
+
+        # Try to use that ticket to get a service ticket.
+        service_creds = self.get_service_creds()
+
+        # This fails due to missing REQUESTER_SID buffer.
+        self._make_tgs_request(creds, service_creds, ticket,
+                               expect_error=(KDC_ERR_TGT_REVOKED,
+                                             KDC_ERR_TKT_EXPIRED))
+
+    def modify_requester_sid_time(self, ticket, sid, lifetime):
+        # Get the krbtgt key.
+        krbtgt_creds = self.get_krbtgt_creds()
+
+        krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+        checksum_keys = {
+            krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key,
+        }
+
+        # Set authtime and starttime to an hour in the past, to show that they
+        # do not affect ticket rejection.
+        start_time = self.get_KerberosTime(offset=-60 * 60)
+
+        # Set the endtime of the ticket relative to our current time, so that
+        # the ticket has 'lifetime' seconds remaining to live.
+        end_time = self.get_KerberosTime(offset=lifetime)
+
+        # Modify the times in the ticket.
+        def modify_ticket_times(enc_part):
+            enc_part['authtime'] = start_time
+            if 'starttime' in enc_part:
+                enc_part['starttime'] = start_time
+
+            enc_part['endtime'] = end_time
+
+            return enc_part
+
+        # We have to set the times in both the ticket and the PAC, otherwise
+        # Heimdal will complain.
+        def modify_pac_time(pac):
+            pac_buffers = pac.buffers
+
+            for pac_buffer in pac_buffers:
+                if pac_buffer.type == krb5pac.PAC_TYPE_LOGON_NAME:
+                    logon_time = self.get_EpochFromKerberosTime(start_time)
+                    pac_buffer.info.logon_time = unix2nttime(logon_time)
+                    break
+            else:
+                self.fail('failed to find LOGON_NAME PAC buffer')
+
+            pac.buffers = pac_buffers
+
+            return pac
+
+        # Add a requester SID to show that the KDC will then accept this
+        # kpasswd ticket as if it were a TGT.
+        def modify_pac_fn(pac):
+            pac = self.add_requester_sid(pac, sid=sid)
+            pac = modify_pac_time(pac)
+            return pac
+
+        # Do the actual modification.
+        return self.modified_ticket(ticket,
+                                    new_ticket_key=krbtgt_key,
+                                    modify_fn=modify_ticket_times,
+                                    modify_pac_fn=modify_pac_fn,
+                                    checksum_keys=checksum_keys)
+
+    # Ensure we cannot perform a TGS-REQ with a kpasswd ticket containing a
+    # requester SID and having a remaining lifetime of two minutes.
+    def test_kpasswd_ticket_requester_sid_tgs(self):
+        creds = self.get_client_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        # Change the sname of the ticket to match that of a TGT.
+        realm = creds.get_realm()
+        krbtgt_sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+                                                 names=['krbtgt', realm])
+        ticket.set_sname(krbtgt_sname)
+
+        # Get the user's SID.
+        samdb = self.get_samdb()
+
+        user_dn = creds.get_dn()
+        user_sid = self.get_objectSid(samdb, user_dn)
+
+        # Modify the ticket to add a requester SID and give it two minutes to
+        # live.
+        ticket = self.modify_requester_sid_time(ticket,
+                                                sid=user_sid,
+                                                lifetime=2 * 60)
+
+        # Try to use that ticket to get a service ticket.
+        service_creds = self.get_service_creds()
+
+        # This fails due to the lifetime being too short.
+        self._make_tgs_request(creds, service_creds, ticket,
+                               expect_error=KDC_ERR_TKT_EXPIRED)
+
+    # Show we can perform a TGS-REQ with a kpasswd ticket containing a
+    # requester SID if the remaining lifetime exceeds two minutes.
+    def test_kpasswd_ticket_requester_sid_lifetime_tgs(self):
+        creds = self.get_client_creds()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=self.get_kpasswd_sname(),
+                              kdc_options='0')
+
+        # Change the sname of the ticket to match that of a TGT.
+        realm = creds.get_realm()
+        krbtgt_sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+                                                 names=['krbtgt', realm])
+        ticket.set_sname(krbtgt_sname)
+
+        # Get the user's SID.
+        samdb = self.get_samdb()
+
+        user_dn = creds.get_dn()
+        user_sid = self.get_objectSid(samdb, user_dn)
+
+        # Modify the ticket to add a requester SID and give it two minutes and
+        # ten seconds to live.
+        ticket = self.modify_requester_sid_time(ticket,
+                                                sid=user_sid,
+                                                lifetime=2 * 60 + 10)
+
+        # Try to use that ticket to get a service ticket.
+        service_creds = self.get_service_creds()
+
+        # This succeeds.
+        self._make_tgs_request(creds, service_creds, ticket,
+                               expect_error=False)
+
+    # Test that kpasswd rejects requests with a service ticket.
+    def test_kpasswd_non_initial(self):
+        # Create an account for testing, and get a TGT.
+        creds = self._get_creds()
+        tgt = self.get_tgt(creds)
+
+        # Get a non-initial ticket to kpasswd.
+        krbtgt_creds = self.get_krbtgt_creds()
+        ticket = self.get_service_ticket(tgt,
+                                         krbtgt_creds,
+                                         service='kadmin',
+                                         target_name='changepw',
+                                         kdc_options='0')
+
+        expected_code = KPASSWD_INITIAL_FLAG_NEEDED
+        expected_msg = b'Expected an initial ticket'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Show that kpasswd accepts requests with a service ticket modified to set
+    # the 'initial' flag.
+    def test_kpasswd_initial(self):
+        # Create an account for testing, and get a TGT.
+        creds = self._get_creds()
+
+        krbtgt_creds = self.get_krbtgt_creds()
+
+        # Get a service ticket, and modify it to set the 'initial' flag.
+        def get_ticket():
+            tgt = self.get_tgt(creds, fresh=True)
+
+            # Get a non-initial ticket to kpasswd.
+            ticket = self.get_service_ticket(tgt,
+                                             krbtgt_creds,
+                                             service='kadmin',
+                                             target_name='changepw',
+                                             kdc_options='0',
+                                             fresh=True)
+
+            set_initial_flag = partial(self.modify_ticket_flag, flag='initial',
+                                       value=True)
+
+            checksum_keys = self.get_krbtgt_checksum_key()
+            return self.modified_ticket(ticket,
+                                        modify_fn=set_initial_flag,
+                                        checksum_keys=checksum_keys)
+
+        expected_code = KPASSWD_SUCCESS
+        expected_msg = b'Password changed'
+
+        ticket = get_ticket()
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        creds.update_password(new_password)
+        ticket = get_ticket()
+
+        # Change the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test that kpasswd rejects requests where the ticket is encrypted with a
+    # key other than the krbtgt's.
+    def test_kpasswd_wrong_key(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        sname = self.get_kpasswd_sname()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=sname,
+                              kdc_options='0')
+
+        # Get a key belonging to the Administrator account.
+        admin_creds = self.get_admin_creds()
+        admin_key = self.TicketDecryptionKey_from_creds(admin_creds)
+        self.assertIsNotNone(admin_key.kvno,
+                             'a kvno is required to tell the DB '
+                             'which key to look up.')
+        checksum_keys = {
+            krb5pac.PAC_TYPE_KDC_CHECKSUM: admin_key,
+        }
+
+        # Re-encrypt the ticket using the Administrator's key.
+        ticket = self.modified_ticket(ticket,
+                                      new_ticket_key=admin_key,
+                                      checksum_keys=checksum_keys)
+
+        # Set the sname of the ticket to that of the Administrator account.
+        admin_sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                                names=['Administrator'])
+        ticket.set_sname(admin_sname)
+
+        expected_code = KPASSWD_HARDERROR
+        expected_msg = b'gensec_update failed - NT_STATUS_LOGON_FAILURE\n'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    def test_kpasswd_wrong_key_service(self):
+        # Create an account for testing.
+        creds = self.get_cached_creds(account_type=self.AccountType.COMPUTER,
+                                      use_cache=False)
+
+        sname = self.get_kpasswd_sname()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=sname,
+                              kdc_options='0')
+
+        # Get a key belonging to our account.
+        our_key = self.TicketDecryptionKey_from_creds(creds)
+        self.assertIsNotNone(our_key.kvno,
+                             'a kvno is required to tell the DB '
+                             'which key to look up.')
+        checksum_keys = {
+            krb5pac.PAC_TYPE_KDC_CHECKSUM: our_key,
+        }
+
+        # Re-encrypt the ticket using our key.
+        ticket = self.modified_ticket(ticket,
+                                      new_ticket_key=our_key,
+                                      checksum_keys=checksum_keys)
+
+        # Set the sname of the ticket to that of our account.
+        username = creds.get_username()
+        sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                          names=username.split('/'))
+        ticket.set_sname(sname)
+
+        expected_code = KPASSWD_HARDERROR
+        expected_msg = b'gensec_update failed - NT_STATUS_LOGON_FAILURE\n'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+    # Test that kpasswd rejects requests where the ticket is encrypted with a
+    # key belonging to a server account other than the krbtgt.
+    def test_kpasswd_wrong_key_server(self):
+        # Create an account for testing.
+        creds = self._get_creds()
+
+        sname = self.get_kpasswd_sname()
+
+        # Get an initial ticket to kpasswd.
+        ticket = self.get_tgt(creds, sname=sname,
+                              kdc_options='0')
+
+        # Get a key belonging to the DC's account.
+        dc_creds = self.get_dc_creds()
+        dc_key = self.TicketDecryptionKey_from_creds(dc_creds)
+        self.assertIsNotNone(dc_key.kvno,
+                             'a kvno is required to tell the DB '
+                             'which key to look up.')
+        checksum_keys = {
+            krb5pac.PAC_TYPE_KDC_CHECKSUM: dc_key,
+        }
+
+        # Re-encrypt the ticket using the DC's key.
+        ticket = self.modified_ticket(ticket,
+                                      new_ticket_key=dc_key,
+                                      checksum_keys=checksum_keys)
+
+        # Set the sname of the ticket to that of the DC's account.
+        dc_username = dc_creds.get_username()
+        dc_sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+                                             names=dc_username.split('/'))
+        ticket.set_sname(dc_sname)
+
+        expected_code = KPASSWD_HARDERROR
+        expected_msg = b'gensec_update failed - NT_STATUS_LOGON_FAILURE\n'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Change the password.
+        self.kpasswd_exchange(ticket,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
+
+if __name__ == '__main__':
+    global_asn1_print = False
+    global_hexdump = False
+    import unittest
+    unittest.main()
diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index 57010ae73bd..4a78a8eadf3 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -500,6 +500,10 @@ class KerberosCredentials(Credentials):
     def get_upn(self):
         return self.upn
 
+    def update_password(self, password):
+        self.set_password(password)
+        self.set_kvno(self.get_kvno() + 1)
+
 
 class KerberosTicketCreds:
     def __init__(self, ticket, session_key,
@@ -518,6 +522,10 @@ class KerberosTicketCreds:
         self.ticket_private = ticket_private
         self.encpart_private = encpart_private
 
+    def set_sname(self, sname):
+        self.ticket['sname'] = sname
+        self.sname = sname
+
 
 class RawKerberosTest(TestCaseInTempDir):
     """A raw Kerberos Test case."""
diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py
index 6bbd96e7a08..a1210ada579 100644
--- a/python/samba/tests/usage.py
+++ b/python/samba/tests/usage.py
@@ -109,6 +109,7 @@ EXCLUDE_USAGE = {
     'python/samba/tests/krb5/alias_tests.py',
     'python/samba/tests/krb5/test_min_domain_uid.py',
     'python/samba/tests/krb5/test_idmap_nss.py',
+    'python/samba/tests/krb5/kpasswd_tests.py',
 }
 
 EXCLUDE_HELP = {
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 692b9ecdd72..9f2b855af4c 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -109,3 +109,29 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
+#
+# Kpasswd tests
+#
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change_expired_password.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_initial.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_seq_number.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_expired_password.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_access.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_no_access.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_only.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_realm_only.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_too_weak.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 095da10238c..c8187ba5db3 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -541,3 +541,29 @@ 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_tgs_rodc_logon_info_sid_mismatch_nonexisting
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_nonexisting
+#
+# Kpasswd tests
+#
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change_expired_password.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_initial.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_seq_number.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_expired_password.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_access.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_no_access.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_only.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_realm_only.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_too_weak.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index c5fdf7fe294..102b17f5376 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -1590,6 +1590,10 @@ planpythontestsuite(
     "ad_dc",
     "samba.tests.krb5.alias_tests",
     environ=krb5_environ)
+planoldpythontestsuite(
+    'ad_dc',
+    'samba.tests.krb5.kpasswd_tests',
+    environ=krb5_environ)
 
 for env in [
         'vampire_dc',
-- 
2.25.1


From 2ee46c16d2aa706b686b50ccb66a2a3ad9852c50 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 27 May 2022 19:21:06 +1200
Subject: [PATCH 72/99] CVE-2022-2031 s4:kpasswd: Correctly generate error
 strings

The error_data we create already has an explicit length, and should not
be zero-terminated, so we omit the trailing null byte. Previously,
Heimdal builds would leave a superfluous trailing null byte on error
strings, while MIT builds would omit the final character.

The two bytes added to the string's length are for the prepended error
code.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Removed MIT KDC 1.20-specific knownfails]
---
 selftest/knownfail_heimdal_kdc | 12 ------------
 selftest/knownfail_mit_kdc     | 15 ---------------
 source4/kdc/kpasswd-helper.c   | 13 ++++++-------
 3 files changed, 6 insertions(+), 34 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 9f2b855af4c..5fd6e4aa0ed 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -114,24 +114,12 @@
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change_expired_password.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_initial.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_seq_number.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_expired_password.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_access.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_no_access.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_only.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_realm_only.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_too_weak.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index c8187ba5db3..6c8d6e45cdd 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -544,26 +544,11 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 #
 # Kpasswd tests
 #
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_change_expired_password.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_initial.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_seq_number.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_expired_password.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_access.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_and_realm_no_access.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_princ_only.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_set_target_realm_only.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_too_weak.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/source4/kdc/kpasswd-helper.c b/source4/kdc/kpasswd-helper.c
index 995f54825b5..55a2f5b3bf6 100644
--- a/source4/kdc/kpasswd-helper.c
+++ b/source4/kdc/kpasswd-helper.c
@@ -48,17 +48,16 @@ bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
 	}
 
 	/*
-	 * The string 's' has two terminating nul-bytes which are also
-	 * reflected by 'slen'. Normally Kerberos doesn't expect that strings
-	 * are nul-terminated, but Heimdal does!
+	 * The string 's' has one terminating nul-byte which is also
+	 * reflected by 'slen'. We subtract it from the length.
 	 */
-#ifndef SAMBA4_USES_HEIMDAL
-	if (slen < 2) {
+	if (slen < 1) {
 		talloc_free(s);
 		return false;
 	}
-	slen -= 2;
-#endif
+	slen--;
+
+	/* Two bytes are added to the length to account for the error code. */
 	if (2 + slen < slen) {
 		talloc_free(s);
 		return false;
-- 
2.25.1


From b1003099c202d05b7d3f570fe313039aebdec3f9 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 18 May 2022 16:48:59 +1200
Subject: [PATCH 73/99] CVE-2022-2031 s4:kpasswd: Don't return AP-REP on
 failure

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Removed MIT KDC 1.20-specific knownfails]
---
 selftest/knownfail_mit_kdc    | 1 -
 source4/kdc/kpasswd-service.c | 2 ++
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 6c8d6e45cdd..41a793ae082 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -545,7 +545,6 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 # Kpasswd tests
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
diff --git a/source4/kdc/kpasswd-service.c b/source4/kdc/kpasswd-service.c
index 061aedc80e5..22e1295c11e 100644
--- a/source4/kdc/kpasswd-service.c
+++ b/source4/kdc/kpasswd-service.c
@@ -256,6 +256,7 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
 				      &kpasswd_dec_reply,
 				      &error_string);
 	if (code != 0) {
+		ap_rep_blob = data_blob_null;
 		error_code = code;
 		goto reply;
 	}
@@ -265,6 +266,7 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
 			     &kpasswd_dec_reply,
 			     &enc_data_blob);
 	if (!NT_STATUS_IS_OK(status)) {
+		ap_rep_blob = data_blob_null;
 		error_code = KRB5_KPASSWD_HARDERROR;
 		error_string = talloc_asprintf(tmp_ctx,
 					       "gensec_wrap failed - %s\n",
-- 
2.25.1


From 38c83abffd325ee23649c190b8ffb3d27a2bdb68 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 27 May 2022 19:29:34 +1200
Subject: [PATCH 74/99] CVE-2022-2031 lib:krb5_wrap: Generate valid error codes
 in smb_krb5_mk_error()

The error code passed in will be an offset from ERROR_TABLE_BASE_krb5,
so we need to subtract that before creating the error. Heimdal does this
internally, so it isn't needed there.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 lib/krb5_wrap/krb5_samba.c | 2 +-
 selftest/knownfail_mit_kdc | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
index 76c2dcd2126..610efcc9b87 100644
--- a/lib/krb5_wrap/krb5_samba.c
+++ b/lib/krb5_wrap/krb5_samba.c
@@ -237,7 +237,7 @@ krb5_error_code smb_krb5_mk_error(krb5_context context,
 		return code;
 	}
 
-	errpkt.error = error_code;
+	errpkt.error = error_code - ERROR_TABLE_BASE_krb5;
 
 	errpkt.text.length = 0;
 	if (e_text != NULL) {
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 41a793ae082..e4300b4d20e 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -545,9 +545,13 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 # Kpasswd tests
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_seq_number.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
-- 
2.25.1


From 481a70c37464d356f60a30c5f51ffae755c4e6f0 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 18 May 2022 16:49:43 +1200
Subject: [PATCH 75/99] CVE-2022-2031 s4:kpasswd: Return a kpasswd error code
 in KRB-ERROR

If we attempt to return an error code outside of Heimdal's allowed range
[KRB5KDC_ERR_NONE, KRB5_ERR_RCSID), it will be replaced with a GENERIC
error, and the error text will be set to the meaningless result of
krb5_get_error_message(). Avoid this by ensuring the error code is in
the correct range.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 selftest/knownfail_heimdal_kdc | 2 --
 selftest/knownfail_mit_kdc     | 4 ----
 source4/kdc/kpasswd-service.c  | 2 +-
 3 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 5fd6e4aa0ed..cb4f190d75f 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -114,9 +114,7 @@
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_seq_number.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index e4300b4d20e..41a793ae082 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -545,13 +545,9 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 # Kpasswd tests
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_empty.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_seq_number.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/source4/kdc/kpasswd-service.c b/source4/kdc/kpasswd-service.c
index 22e1295c11e..379ddebf3ad 100644
--- a/source4/kdc/kpasswd-service.c
+++ b/source4/kdc/kpasswd-service.c
@@ -315,7 +315,7 @@ reply:
 		}
 
 		code = smb_krb5_mk_error(kdc->smb_krb5_context->krb5_context,
-					 error_code,
+					 KRB5KDC_ERR_NONE + error_code,
 					 NULL, /* e_text */
 					 &k_dec_data,
 					 NULL, /* client */
-- 
2.25.1


From 9da789c73dd6675789b93fc0df0dfc8b274a86c3 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 18 May 2022 16:06:31 +1200
Subject: [PATCH 76/99] CVE-2022-2031 gensec_krb5: Add helper function to check
 if client sent an initial ticket

This will be used in the kpasswd service to ensure that the client has
an initial ticket to kadmin/changepw, and not a service ticket.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/auth/gensec/gensec_krb5.c          | 20 +-----
 source4/auth/gensec/gensec_krb5_helpers.c  | 72 ++++++++++++++++++++++
 source4/auth/gensec/gensec_krb5_helpers.h  | 32 ++++++++++
 source4/auth/gensec/gensec_krb5_internal.h | 47 ++++++++++++++
 source4/auth/gensec/wscript_build          |  4 ++
 5 files changed, 157 insertions(+), 18 deletions(-)
 create mode 100644 source4/auth/gensec/gensec_krb5_helpers.c
 create mode 100644 source4/auth/gensec/gensec_krb5_helpers.h
 create mode 100644 source4/auth/gensec/gensec_krb5_internal.h

diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index 7d87b3ac6b9..104e4639c44 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -44,27 +44,11 @@
 #include "../lib/util/asn1.h"
 #include "auth/kerberos/pac_utils.h"
 #include "gensec_krb5.h"
+#include "gensec_krb5_internal.h"
+#include "gensec_krb5_helpers.h"
 
 _PUBLIC_ NTSTATUS gensec_krb5_init(TALLOC_CTX *);
 
-enum GENSEC_KRB5_STATE {
-	GENSEC_KRB5_SERVER_START,
-	GENSEC_KRB5_CLIENT_START,
-	GENSEC_KRB5_CLIENT_MUTUAL_AUTH,
-	GENSEC_KRB5_DONE
-};
-
-struct gensec_krb5_state {
-	enum GENSEC_KRB5_STATE state_position;
-	struct smb_krb5_context *smb_krb5_context;
-	krb5_auth_context auth_context;
-	krb5_data enc_ticket;
-	krb5_keyblock *keyblock;
-	krb5_ticket *ticket;
-	bool gssapi;
-	krb5_flags ap_req_options;
-};
-
 static int gensec_krb5_destroy(struct gensec_krb5_state *gensec_krb5_state)
 {
 	if (!gensec_krb5_state->smb_krb5_context) {
diff --git a/source4/auth/gensec/gensec_krb5_helpers.c b/source4/auth/gensec/gensec_krb5_helpers.c
new file mode 100644
index 00000000000..21f2f1e884e
--- /dev/null
+++ b/source4/auth/gensec/gensec_krb5_helpers.c
@@ -0,0 +1,72 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Kerberos backend for GENSEC
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Luke Howard 2002-2003
+   Copyright (C) Stefan Metzmacher 2004-2005
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_internal.h"
+#include "gensec_krb5_internal.h"
+#include "gensec_krb5_helpers.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+
+static struct gensec_krb5_state *get_private_state(const struct gensec_security *gensec_security)
+{
+	struct gensec_krb5_state *gensec_krb5_state = NULL;
+
+	if (strcmp(gensec_security->ops->name, "krb5") != 0) {
+		/* We require that the krb5 mechanism is being used. */
+		return NULL;
+	}
+
+	gensec_krb5_state = talloc_get_type(gensec_security->private_data,
+					    struct gensec_krb5_state);
+	return gensec_krb5_state;
+}
+
+/*
+ * Returns 1 if our ticket has the initial flag set, 0 if not, and -1 in case of
+ * error.
+ */
+int gensec_krb5_initial_ticket(const struct gensec_security *gensec_security)
+{
+	struct gensec_krb5_state *gensec_krb5_state = NULL;
+
+	gensec_krb5_state = get_private_state(gensec_security);
+	if (gensec_krb5_state == NULL) {
+		return -1;
+	}
+
+	if (gensec_krb5_state->ticket == NULL) {
+		/* We don't have a ticket */
+		return -1;
+	}
+
+#ifdef SAMBA4_USES_HEIMDAL
+	return gensec_krb5_state->ticket->ticket.flags.initial;
+#else /* MIT KERBEROS */
+	return (gensec_krb5_state->ticket->enc_part2->flags & TKT_FLG_INITIAL) ? 1 : 0;
+#endif /* SAMBA4_USES_HEIMDAL */
+}
diff --git a/source4/auth/gensec/gensec_krb5_helpers.h b/source4/auth/gensec/gensec_krb5_helpers.h
new file mode 100644
index 00000000000..d7b694dad0c
--- /dev/null
+++ b/source4/auth/gensec/gensec_krb5_helpers.h
@@ -0,0 +1,32 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Kerberos backend for GENSEC
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Luke Howard 2002-2003
+   Copyright (C) Stefan Metzmacher 2004-2005
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+struct gensec_security;
+
+/*
+ * Returns 1 if our ticket has the initial flag set, 0 if not, and -1 in case of
+ * error.
+ */
+int gensec_krb5_initial_ticket(const struct gensec_security *gensec_security);
diff --git a/source4/auth/gensec/gensec_krb5_internal.h b/source4/auth/gensec/gensec_krb5_internal.h
new file mode 100644
index 00000000000..0bb796f1b2a
--- /dev/null
+++ b/source4/auth/gensec/gensec_krb5_internal.h
@@ -0,0 +1,47 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Kerberos backend for GENSEC
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+   Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Luke Howard 2002-2003
+   Copyright (C) Stefan Metzmacher 2004-2005
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "auth/gensec/gensec.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+
+enum GENSEC_KRB5_STATE {
+	GENSEC_KRB5_SERVER_START,
+	GENSEC_KRB5_CLIENT_START,
+	GENSEC_KRB5_CLIENT_MUTUAL_AUTH,
+	GENSEC_KRB5_DONE
+};
+
+struct gensec_krb5_state {
+	enum GENSEC_KRB5_STATE state_position;
+	struct smb_krb5_context *smb_krb5_context;
+	krb5_auth_context auth_context;
+	krb5_data enc_ticket;
+	krb5_keyblock *keyblock;
+	krb5_ticket *ticket;
+	bool gssapi;
+	krb5_flags ap_req_options;
+};
diff --git a/source4/auth/gensec/wscript_build b/source4/auth/gensec/wscript_build
index d14a50ff273..20271f1665b 100644
--- a/source4/auth/gensec/wscript_build
+++ b/source4/auth/gensec/wscript_build
@@ -18,6 +18,10 @@ bld.SAMBA_MODULE('gensec_krb5',
         enabled=bld.AD_DC_BUILD_IS_ENABLED()
 	)
 
+bld.SAMBA_SUBSYSTEM('gensec_krb5_helpers',
+    source='gensec_krb5_helpers.c',
+    deps='gensec_krb5',
+    enabled=bld.AD_DC_BUILD_IS_ENABLED())
 
 bld.SAMBA_MODULE('gensec_gssapi',
 	source='gensec_gssapi.c',
-- 
2.25.1


From 298884abb35db7b6a8c6100dfd7bb8b57b1117fd Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 18 May 2022 16:52:41 +1200
Subject: [PATCH 77/99] CVE-2022-2031 s4:kpasswd: Require an initial ticket

Ensure that for password changes the client uses an AS-REQ to get the
ticket to kpasswd, and not a TGS-REQ.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Removed MIT KDC 1.20-specific knownfails]
---
 selftest/knownfail_heimdal_kdc        |  1 -
 selftest/knownfail_mit_kdc            |  1 -
 source4/kdc/kpasswd-service-heimdal.c | 17 +++++++++++++++++
 source4/kdc/kpasswd-service-mit.c     | 17 +++++++++++++++++
 source4/kdc/wscript_build             |  1 +
 5 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index cb4f190d75f..ab7230060ab 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -115,7 +115,6 @@
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 41a793ae082..0389672e5d9 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -546,7 +546,6 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_non_initial.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
diff --git a/source4/kdc/kpasswd-service-heimdal.c b/source4/kdc/kpasswd-service-heimdal.c
index c804852c3a7..1a6c2b60d03 100644
--- a/source4/kdc/kpasswd-service-heimdal.c
+++ b/source4/kdc/kpasswd-service-heimdal.c
@@ -24,6 +24,7 @@
 #include "param/param.h"
 #include "auth/auth.h"
 #include "auth/gensec/gensec.h"
+#include "gensec_krb5_helpers.h"
 #include "kdc/kdc-server.h"
 #include "kdc/kpasswd_glue.h"
 #include "kdc/kpasswd-service.h"
@@ -31,6 +32,7 @@
 
 static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
 					       TALLOC_CTX *mem_ctx,
+					       const struct gensec_security *gensec_security,
 					       struct auth_session_info *session_info,
 					       DATA_BLOB *password,
 					       DATA_BLOB *kpasswd_reply,
@@ -42,6 +44,17 @@ static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
 	const char *reject_string = NULL;
 	struct samr_DomInfo1 *dominfo;
 	bool ok;
+	int ret;
+
+	/*
+	 * We're doing a password change (rather than a password set), so check
+	 * that we were given an initial ticket.
+	 */
+	ret = gensec_krb5_initial_ticket(gensec_security);
+	if (ret != 1) {
+		*error_string = "Expected an initial ticket";
+		return KRB5_KPASSWD_INITIAL_FLAG_NEEDED;
+	}
 
 	status = samdb_kpasswd_change_password(mem_ctx,
 					       kdc->task->lp_ctx,
@@ -81,6 +94,7 @@ static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
 
 static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 					    TALLOC_CTX *mem_ctx,
+					    const struct gensec_security *gensec_security,
 					    struct auth_session_info *session_info,
 					    DATA_BLOB *decoded_data,
 					    DATA_BLOB *kpasswd_reply,
@@ -173,6 +187,7 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 		free_ChangePasswdDataMS(&chpw);
 		return kpasswd_change_password(kdc,
 					       mem_ctx,
+					       gensec_security,
 					       session_info,
 					       &password,
 					       kpasswd_reply,
@@ -272,6 +287,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 
 		return kpasswd_change_password(kdc,
 					       mem_ctx,
+					       gensec_security,
 					       session_info,
 					       &password,
 					       kpasswd_reply,
@@ -280,6 +296,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 	case KRB5_KPASSWD_VERS_SETPW: {
 		return kpasswd_set_password(kdc,
 					    mem_ctx,
+					    gensec_security,
 					    session_info,
 					    decoded_data,
 					    kpasswd_reply,
diff --git a/source4/kdc/kpasswd-service-mit.c b/source4/kdc/kpasswd-service-mit.c
index 9c4d2801669..de4c6f3f622 100644
--- a/source4/kdc/kpasswd-service-mit.c
+++ b/source4/kdc/kpasswd-service-mit.c
@@ -24,6 +24,7 @@
 #include "param/param.h"
 #include "auth/auth.h"
 #include "auth/gensec/gensec.h"
+#include "gensec_krb5_helpers.h"
 #include "kdc/kdc-server.h"
 #include "kdc/kpasswd_glue.h"
 #include "kdc/kpasswd-service.h"
@@ -84,6 +85,7 @@ out:
 
 static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
 					       TALLOC_CTX *mem_ctx,
+					       const struct gensec_security *gensec_security,
 					       struct auth_session_info *session_info,
 					       DATA_BLOB *password,
 					       DATA_BLOB *kpasswd_reply,
@@ -95,6 +97,17 @@ static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
 	const char *reject_string = NULL;
 	struct samr_DomInfo1 *dominfo;
 	bool ok;
+	int ret;
+
+	/*
+	 * We're doing a password change (rather than a password set), so check
+	 * that we were given an initial ticket.
+	 */
+	ret = gensec_krb5_initial_ticket(gensec_security);
+	if (ret != 1) {
+		*error_string = "Expected an initial ticket";
+		return KRB5_KPASSWD_INITIAL_FLAG_NEEDED;
+	}
 
 	status = samdb_kpasswd_change_password(mem_ctx,
 					       kdc->task->lp_ctx,
@@ -134,6 +147,7 @@ static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
 
 static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 					    TALLOC_CTX *mem_ctx,
+					    const struct gensec_security *gensec_security,
 					    struct auth_session_info *session_info,
 					    DATA_BLOB *decoded_data,
 					    DATA_BLOB *kpasswd_reply,
@@ -250,6 +264,7 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 
 		return kpasswd_change_password(kdc,
 					       mem_ctx,
+					       gensec_security,
 					       session_info,
 					       &password,
 					       kpasswd_reply,
@@ -350,6 +365,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 
 		return kpasswd_change_password(kdc,
 					       mem_ctx,
+					       gensec_security,
 					       session_info,
 					       &password,
 					       kpasswd_reply,
@@ -358,6 +374,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 	case RFC3244_VERSION: {
 		return kpasswd_set_password(kdc,
 					    mem_ctx,
+					    gensec_security,
 					    session_info,
 					    decoded_data,
 					    kpasswd_reply,
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index 0edca94e75f..13ba3947cf6 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -88,6 +88,7 @@ bld.SAMBA_SUBSYSTEM('KPASSWD-SERVICE',
                          krb5samba
                          samba_server_gensec
                          KPASSWD_GLUE
+                         gensec_krb5_helpers
                          ''')
 
 bld.SAMBA_SUBSYSTEM('KDC-GLUE',
-- 
2.25.1


From a1df5b86e967dc190af5ba2ba07d8ef8b400b4b1 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 18 May 2022 17:11:49 +1200
Subject: [PATCH 78/99] s4:kpasswd: Restructure code for clarity

View with 'git show -b'.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/kdc/kpasswd-service-heimdal.c | 46 +++++++++++++--------------
 1 file changed, 22 insertions(+), 24 deletions(-)

diff --git a/source4/kdc/kpasswd-service-heimdal.c b/source4/kdc/kpasswd-service-heimdal.c
index 1a6c2b60d03..a0352d1ad35 100644
--- a/source4/kdc/kpasswd-service-heimdal.c
+++ b/source4/kdc/kpasswd-service-heimdal.c
@@ -160,30 +160,7 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 		return 0;
 	}
 
-	if (chpw.targname != NULL && chpw.targrealm != NULL) {
-		code = krb5_build_principal_ext(context,
-					       &target_principal,
-					       strlen(*chpw.targrealm),
-					       *chpw.targrealm,
-					       0);
-		if (code != 0) {
-			free_ChangePasswdDataMS(&chpw);
-			return kpasswd_make_error_reply(mem_ctx,
-							KRB5_KPASSWD_MALFORMED,
-							"Failed to parse principal",
-							kpasswd_reply);
-		}
-		code = copy_PrincipalName(chpw.targname,
-					  &target_principal->name);
-		if (code != 0) {
-			free_ChangePasswdDataMS(&chpw);
-			krb5_free_principal(context, target_principal);
-			return kpasswd_make_error_reply(mem_ctx,
-							KRB5_KPASSWD_MALFORMED,
-							"Failed to parse principal",
-							kpasswd_reply);
-		}
-	} else {
+	if (chpw.targname == NULL || chpw.targrealm == NULL) {
 		free_ChangePasswdDataMS(&chpw);
 		return kpasswd_change_password(kdc,
 					       mem_ctx,
@@ -193,7 +170,28 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
 					       kpasswd_reply,
 					       error_string);
 	}
+	code = krb5_build_principal_ext(context,
+					&target_principal,
+					strlen(*chpw.targrealm),
+					*chpw.targrealm,
+					0);
+	if (code != 0) {
+		free_ChangePasswdDataMS(&chpw);
+		return kpasswd_make_error_reply(mem_ctx,
+						KRB5_KPASSWD_MALFORMED,
+						"Failed to parse principal",
+						kpasswd_reply);
+	}
+	code = copy_PrincipalName(chpw.targname,
+				  &target_principal->name);
 	free_ChangePasswdDataMS(&chpw);
+	if (code != 0) {
+		krb5_free_principal(context, target_principal);
+		return kpasswd_make_error_reply(mem_ctx,
+						KRB5_KPASSWD_MALFORMED,
+						"Failed to parse principal",
+						kpasswd_reply);
+	}
 
 	if (target_principal->name.name_string.len >= 2) {
 		is_service_principal = true;
-- 
2.25.1


From 981948677c895e4e1d3b074f8a1a9c82fd65a80a Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Tue, 24 May 2022 10:17:00 +0200
Subject: [PATCH 79/99] CVE-2022-2031 testprogs: Fix auth with smbclient and
 krb5 ccache

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

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
---
 testprogs/blackbox/test_kpasswd_heimdal.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/testprogs/blackbox/test_kpasswd_heimdal.sh b/testprogs/blackbox/test_kpasswd_heimdal.sh
index 43f38b09de2..a73c6665a18 100755
--- a/testprogs/blackbox/test_kpasswd_heimdal.sh
+++ b/testprogs/blackbox/test_kpasswd_heimdal.sh
@@ -71,7 +71,7 @@ testit "kinit with user password" \
 	do_kinit $TEST_PRINCIPAL $TEST_PASSWORD || failed=`expr $failed + 1`
 
 test_smbclient "Test login with user kerberos ccache" \
-	"ls" "$SMB_UNC" --use-kerberos=required || failed=`expr $failed + 1`
+	"ls" "$SMB_UNC" --use-krb5-ccache=${KRB5CCNAME} || failed=`expr $failed + 1`
 
 testit "change user password with 'samba-tool user password' (unforced)" \
 	$VALGRIND $PYTHON $samba_tool user password -W$DOMAIN -U$TEST_USERNAME%$TEST_PASSWORD --use-kerberos=off --newpassword=$TEST_PASSWORD_NEW || failed=`expr $failed + 1`
@@ -84,7 +84,7 @@ testit "kinit with user password" \
 	do_kinit $TEST_PRINCIPAL $TEST_PASSWORD || failed=`expr $failed + 1`
 
 test_smbclient "Test login with user kerberos ccache" \
-	"ls" "$SMB_UNC" --use-kerberos=required || failed=`expr $failed + 1`
+	"ls" "$SMB_UNC" --use-krb5-ccache=${KRB5CCNAME} || failed=`expr $failed + 1`
 
 ###########################################################
 ### check that a short password is rejected
-- 
2.25.1


From 5dd0ef1991944a740b1d0107487d25d1acf5ebef Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Thu, 19 May 2022 16:35:28 +0200
Subject: [PATCH 80/99] CVE-2022-2031 testprogs: Add kadmin/changepw
 canonicalization test with MIT kpasswd

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

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
---
 selftest/knownfail.d/kadmin_changepw       |  1 +
 testprogs/blackbox/test_kpasswd_heimdal.sh | 35 +++++++++++++++++++++-
 2 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 selftest/knownfail.d/kadmin_changepw

diff --git a/selftest/knownfail.d/kadmin_changepw b/selftest/knownfail.d/kadmin_changepw
new file mode 100644
index 00000000000..97c14793ea5
--- /dev/null
+++ b/selftest/knownfail.d/kadmin_changepw
@@ -0,0 +1 @@
+^samba4.blackbox.kpasswd.MIT kpasswd.change.user.password
diff --git a/testprogs/blackbox/test_kpasswd_heimdal.sh b/testprogs/blackbox/test_kpasswd_heimdal.sh
index a73c6665a18..698044a3fd3 100755
--- a/testprogs/blackbox/test_kpasswd_heimdal.sh
+++ b/testprogs/blackbox/test_kpasswd_heimdal.sh
@@ -7,7 +7,7 @@
 
 if [ $# -lt 6 ]; then
 cat <<EOF
-Usage: test_passwords.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX SMBCLIENT
+Usage: test_kpasswd_heimdal.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX SMBCLIENT
 EOF
 exit 1;
 fi
@@ -27,6 +27,8 @@ smbclient="$samba_bindir/smbclient"
 samba_kinit=$samba_bindir/samba4kinit
 samba_kpasswd=$samba_bindir/samba4kpasswd
 
+mit_kpasswd="$(command -v kpasswd)"
+
 samba_tool="$samba_bindir/samba-tool"
 net_tool="$samba_bindir/net"
 texpect="$samba_bindir/texpect"
@@ -141,6 +143,37 @@ testit "kpasswd change user password" \
 TEST_PASSWORD=$TEST_PASSWORD_NEW
 TEST_PASSWORD_NEW="testPaSS@03%"
 
+###########################################################
+### CVE-2022-XXXXX
+###########################################################
+
+if [ -n "${mit_kpasswd}" ]; then
+	cat > "${PREFIX}/tmpkpasswdscript" <<EOF
+expect Password for ${TEST_PRINCIPAL}
+password ${TEST_PASSWORD}\n
+expect Enter new password
+send ${TEST_PASSWORD_NEW}\n
+expect Enter it again
+send ${TEST_PASSWORD_NEW}\n
+expect Password changed.
+EOF
+
+	SAVE_KRB5_CONFIG="${KRB5_CONFIG}"
+	KRB5_CONFIG="${PREFIX}/tmpkrb5.conf"
+	export KRB5_CONFIG
+	sed -e 's/\[libdefaults\]/[libdefaults]\n canonicalize = yes/' \
+		"${SAVE_KRB5_CONFIG}" > "${KRB5_CONFIG}"
+	testit "MIT kpasswd change user password" \
+		"${texpect}" "${PREFIX}/tmpkpasswdscript" "${mit_kpasswd}" \
+		"${TEST_PRINCIPAL}" ||
+		failed=$((failed + 1))
+	KRB5_CONFIG="${SAVE_KRB5_CONFIG}"
+	export KRB5_CONFIG
+fi
+
+TEST_PASSWORD="${TEST_PASSWORD_NEW}"
+TEST_PASSWORD_NEW="testPaSS@03force%"
+
 ###########################################################
 ### Force password change at login
 ###########################################################
-- 
2.25.1


From 3fd067c7d63e132a84bfc155769012e4261a9f07 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Tue, 24 May 2022 09:54:18 +0200
Subject: [PATCH 81/99] CVE-2022-2031 s4:kdc: Implement is_kadmin_changepw()
 helper function

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

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>

[jsutton@samba.org Adapted entry to entry_ex->entry]
---
 source4/kdc/db-glue.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 5752ffb821c..45159e6e64d 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -816,6 +816,14 @@ static int principal_comp_strcmp(krb5_context context,
 					 component, string, false);
 }
 
+static bool is_kadmin_changepw(krb5_context context,
+			       krb5_const_principal principal)
+{
+	return krb5_princ_size(context, principal) == 2 &&
+		(principal_comp_strcmp(context, principal, 0, "kadmin") == 0) &&
+		(principal_comp_strcmp(context, principal, 1, "changepw") == 0);
+}
+
 /*
  * Construct an hdb_entry from a directory entry.
  */
@@ -1110,11 +1118,9 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 		 * 'change password', as otherwise we could get into
 		 * trouble, and not enforce the password expirty.
 		 * Instead, only do it when request is for the kpasswd service */
-		if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER
-		    && krb5_princ_size(context, principal) == 2
-		    && (principal_comp_strcmp(context, principal, 0, "kadmin") == 0)
-		    && (principal_comp_strcmp(context, principal, 1, "changepw") == 0)
-		    && lpcfg_is_my_domain_or_realm(lp_ctx, realm)) {
+		if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER &&
+		    is_kadmin_changepw(context, principal) &&
+		    lpcfg_is_my_domain_or_realm(lp_ctx, realm)) {
 			entry_ex->entry.flags.change_pw = 1;
 		}
 
-- 
2.25.1


From 5e7d75d8754d157d10e3e7d730445bddd91e5b9e Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 18 May 2022 16:56:01 +1200
Subject: [PATCH 82/99] CVE-2022-2031 s4:kdc: Split out a
 samba_kdc_get_entry_principal() function

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Adapted entry to entry_ex->entry]

[jsutton@samba.org Fixed conflicts caused by superfluous whitespace]
---
 source4/kdc/db-glue.c | 192 +++++++++++++++++++++++-------------------
 1 file changed, 107 insertions(+), 85 deletions(-)

diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 45159e6e64d..ac0c206b5c1 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -824,6 +824,101 @@ static bool is_kadmin_changepw(krb5_context context,
 		(principal_comp_strcmp(context, principal, 1, "changepw") == 0);
 }
 
+static krb5_error_code samba_kdc_get_entry_principal(
+		krb5_context context,
+		struct samba_kdc_db_context *kdc_db_ctx,
+		const char *samAccountName,
+		enum samba_kdc_ent_type ent_type,
+		unsigned flags,
+		krb5_const_principal in_princ,
+		krb5_principal *out_princ)
+{
+	struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
+	krb5_error_code ret = 0;
+
+	/*
+	 * If we are set to canonicalize, we get back the fixed UPPER
+	 * case realm, and the real username (ie matching LDAP
+	 * samAccountName)
+	 *
+	 * Otherwise, if we are set to enterprise, we
+	 * get back the whole principal as-sent
+	 *
+	 * Finally, if we are not set to canonicalize, we get back the
+	 * fixed UPPER case realm, but the as-sent username
+	 */
+
+	if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
+		if (flags & (SDB_F_CANON|SDB_F_FORCE_CANON)) {
+			/*
+			 * When requested to do so, ensure that the
+			 * both realm values in the principal are set
+			 * to the upper case, canonical realm
+			 */
+			ret = smb_krb5_make_principal(context, out_princ,
+						      lpcfg_realm(lp_ctx), "krbtgt",
+						      lpcfg_realm(lp_ctx), NULL);
+			if (ret) {
+				return ret;
+			}
+			smb_krb5_principal_set_type(context, *out_princ, KRB5_NT_SRV_INST);
+		} else {
+			ret = krb5_copy_principal(context, in_princ, out_princ);
+			if (ret) {
+				return ret;
+			}
+			/*
+			 * this appears to be required regardless of
+			 * the canonicalize flag from the client
+			 */
+			ret = smb_krb5_principal_set_realm(context, *out_princ, lpcfg_realm(lp_ctx));
+			if (ret) {
+				return ret;
+			}
+		}
+
+	} else if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && in_princ == NULL) {
+		ret = smb_krb5_make_principal(context, out_princ, lpcfg_realm(lp_ctx), samAccountName, NULL);
+		if (ret) {
+			return ret;
+		}
+	} else if ((flags & SDB_F_FORCE_CANON) ||
+		   ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ))) {
+		/*
+		 * SDB_F_CANON maps from the canonicalize flag in the
+		 * packet, and has a different meaning between AS-REQ
+		 * and TGS-REQ.  We only change the principal in the AS-REQ case
+		 *
+		 * The SDB_F_FORCE_CANON if for new MIT KDC code that wants
+		 * the canonical name in all lookups, and takes care to
+		 * canonicalize only when appropriate.
+		 */
+		ret = smb_krb5_make_principal(context, out_princ, lpcfg_realm(lp_ctx), samAccountName, NULL);
+		if (ret) {
+			return ret;
+		}
+	} else {
+		ret = krb5_copy_principal(context, in_princ, out_princ);
+		if (ret) {
+			return ret;
+		}
+
+		/* While we have copied the client principal, tests
+		 * show that Win2k3 returns the 'corrected' realm, not
+		 * the client-specified realm.  This code attempts to
+		 * replace the client principal's realm with the one
+		 * we determine from our records */
+
+		/* this has to be with malloc() */
+		ret = smb_krb5_principal_set_realm(context, *out_princ, lpcfg_realm(lp_ctx));
+		if (ret) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * Construct an hdb_entry from a directory entry.
  */
@@ -913,93 +1008,8 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 		userAccountControl |= msDS_User_Account_Control_Computed;
 	}
 
-	/* 
-	 * If we are set to canonicalize, we get back the fixed UPPER
-	 * case realm, and the real username (ie matching LDAP
-	 * samAccountName) 
-	 *
-	 * Otherwise, if we are set to enterprise, we
-	 * get back the whole principal as-sent 
-	 *
-	 * Finally, if we are not set to canonicalize, we get back the
-	 * fixed UPPER case realm, but the as-sent username
-	 */
-
 	if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
 		p->is_krbtgt = true;
-
-		if (flags & (SDB_F_CANON|SDB_F_FORCE_CANON)) {
-			/*
-			 * When requested to do so, ensure that the
-			 * both realm values in the principal are set
-			 * to the upper case, canonical realm
-			 */
-			ret = smb_krb5_make_principal(context, &entry_ex->entry.principal,
-						      lpcfg_realm(lp_ctx), "krbtgt",
-						      lpcfg_realm(lp_ctx), NULL);
-			if (ret) {
-				krb5_clear_error_message(context);
-				goto out;
-			}
-			smb_krb5_principal_set_type(context, entry_ex->entry.principal, KRB5_NT_SRV_INST);
-		} else {
-			ret = krb5_copy_principal(context, principal, &entry_ex->entry.principal);
-			if (ret) {
-				krb5_clear_error_message(context);
-				goto out;
-			}
-			/*
-			 * this appears to be required regardless of
-			 * the canonicalize flag from the client
-			 */
-			ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
-			if (ret) {
-				krb5_clear_error_message(context);
-				goto out;
-			}
-		}
-
-	} else if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && principal == NULL) {
-		ret = smb_krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
-		if (ret) {
-			krb5_clear_error_message(context);
-			goto out;
-		}
-	} else if ((flags & SDB_F_FORCE_CANON) ||
-		   ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ))) {
-		/*
-		 * SDB_F_CANON maps from the canonicalize flag in the
-		 * packet, and has a different meaning between AS-REQ
-		 * and TGS-REQ.  We only change the principal in the AS-REQ case
-		 *
-		 * The SDB_F_FORCE_CANON if for new MIT KDC code that wants
-		 * the canonical name in all lookups, and takes care to
-		 * canonicalize only when appropriate.
-		 */
-		ret = smb_krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
-		if (ret) {
-			krb5_clear_error_message(context);
-			goto out;
-		}
-	} else {
-		ret = krb5_copy_principal(context, principal, &entry_ex->entry.principal);
-		if (ret) {
-			krb5_clear_error_message(context);
-			goto out;
-		}
-
-		/* While we have copied the client principal, tests
-		 * show that Win2k3 returns the 'corrected' realm, not
-		 * the client-specified realm.  This code attempts to
-		 * replace the client principal's realm with the one
-		 * we determine from our records */
-
-		/* this has to be with malloc() */
-		ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
-		if (ret) {
-			krb5_clear_error_message(context);
-			goto out;
-		}
 	}
 
 	/* First try and figure out the flags based on the userAccountControl */
@@ -1185,6 +1195,18 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 		}
 	}
 
+	ret = samba_kdc_get_entry_principal(context,
+					    kdc_db_ctx,
+					    samAccountName,
+					    ent_type,
+					    flags,
+					    principal,
+					    &entry_ex->entry.principal);
+	if (ret != 0) {
+		krb5_clear_error_message(context);
+		goto out;
+	}
+
 	entry_ex->entry.valid_start = NULL;
 
 	entry_ex->entry.max_life = malloc(sizeof(*entry_ex->entry.max_life));
-- 
2.25.1


From 8b9fe095b91ce62338829a6ac7012170e6af8898 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 25 May 2022 17:19:58 +1200
Subject: [PATCH 83/99] CVE-2022-2031 s4:kdc: Refactor
 samba_kdc_get_entry_principal()

This eliminates some duplicate branches.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Pair-Programmed-With: Andreas Schneider <asn@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/kdc/db-glue.c | 116 ++++++++++++++++++++----------------------
 1 file changed, 55 insertions(+), 61 deletions(-)

diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index ac0c206b5c1..385c118a073 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -834,7 +834,8 @@ static krb5_error_code samba_kdc_get_entry_principal(
 		krb5_principal *out_princ)
 {
 	struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
-	krb5_error_code ret = 0;
+	krb5_error_code code = 0;
+	bool canon = flags & (SDB_F_CANON|SDB_F_FORCE_CANON);
 
 	/*
 	 * If we are set to canonicalize, we get back the fixed UPPER
@@ -848,75 +849,68 @@ static krb5_error_code samba_kdc_get_entry_principal(
 	 * fixed UPPER case realm, but the as-sent username
 	 */
 
-	if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
-		if (flags & (SDB_F_CANON|SDB_F_FORCE_CANON)) {
-			/*
-			 * When requested to do so, ensure that the
-			 * both realm values in the principal are set
-			 * to the upper case, canonical realm
-			 */
-			ret = smb_krb5_make_principal(context, out_princ,
-						      lpcfg_realm(lp_ctx), "krbtgt",
-						      lpcfg_realm(lp_ctx), NULL);
-			if (ret) {
-				return ret;
-			}
-			smb_krb5_principal_set_type(context, *out_princ, KRB5_NT_SRV_INST);
-		} else {
-			ret = krb5_copy_principal(context, in_princ, out_princ);
-			if (ret) {
-				return ret;
-			}
-			/*
-			 * this appears to be required regardless of
-			 * the canonicalize flag from the client
-			 */
-			ret = smb_krb5_principal_set_realm(context, *out_princ, lpcfg_realm(lp_ctx));
-			if (ret) {
-				return ret;
-			}
-		}
+	if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT && canon) {
+		/*
+		 * When requested to do so, ensure that the
+		 * both realm values in the principal are set
+		 * to the upper case, canonical realm
+		 */
+		code = smb_krb5_make_principal(context,
+					       out_princ,
+					       lpcfg_realm(lp_ctx),
+					       "krbtgt",
+					       lpcfg_realm(lp_ctx),
+					       NULL);
+		if (code != 0) {
+			return code;
+		}
+		smb_krb5_principal_set_type(context,
+					    *out_princ,
+					    KRB5_NT_SRV_INST);
 
-	} else if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && in_princ == NULL) {
-		ret = smb_krb5_make_principal(context, out_princ, lpcfg_realm(lp_ctx), samAccountName, NULL);
-		if (ret) {
-			return ret;
-		}
-	} else if ((flags & SDB_F_FORCE_CANON) ||
-		   ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ))) {
+		return 0;
+	}
+
+	if ((canon && flags & (SDB_F_FORCE_CANON|SDB_F_FOR_AS_REQ)) ||
+	    (ent_type == SAMBA_KDC_ENT_TYPE_ANY && in_princ == NULL)) {
 		/*
 		 * SDB_F_CANON maps from the canonicalize flag in the
 		 * packet, and has a different meaning between AS-REQ
-		 * and TGS-REQ.  We only change the principal in the AS-REQ case
+		 * and TGS-REQ.  We only change the principal in the
+		 * AS-REQ case.
 		 *
-		 * The SDB_F_FORCE_CANON if for new MIT KDC code that wants
-		 * the canonical name in all lookups, and takes care to
-		 * canonicalize only when appropriate.
+		 * The SDB_F_FORCE_CANON if for new MIT KDC code that
+		 * wants the canonical name in all lookups, and takes
+		 * care to canonicalize only when appropriate.
 		 */
-		ret = smb_krb5_make_principal(context, out_princ, lpcfg_realm(lp_ctx), samAccountName, NULL);
-		if (ret) {
-			return ret;
-		}
-	} else {
-		ret = krb5_copy_principal(context, in_princ, out_princ);
-		if (ret) {
-			return ret;
-		}
-
-		/* While we have copied the client principal, tests
-		 * show that Win2k3 returns the 'corrected' realm, not
-		 * the client-specified realm.  This code attempts to
-		 * replace the client principal's realm with the one
-		 * we determine from our records */
+		code = smb_krb5_make_principal(context,
+					      out_princ,
+					      lpcfg_realm(lp_ctx),
+					      samAccountName,
+					      NULL);
+		return code;
+	}
 
-		/* this has to be with malloc() */
-		ret = smb_krb5_principal_set_realm(context, *out_princ, lpcfg_realm(lp_ctx));
-		if (ret) {
-			return ret;
-		}
+	/*
+	 * For a krbtgt entry, this appears to be required regardless of the
+	 * canonicalize flag from the client.
+	 */
+	code = krb5_copy_principal(context, in_princ, out_princ);
+	if (code != 0) {
+		return code;
 	}
 
-	return 0;
+	/*
+	 * While we have copied the client principal, tests show that Win2k3
+	 * returns the 'corrected' realm, not the client-specified realm.  This
+	 * code attempts to replace the client principal's realm with the one
+	 * we determine from our records
+	 */
+	code = smb_krb5_principal_set_realm(context,
+					    *out_princ,
+					    lpcfg_realm(lp_ctx));
+
+	return code;
 }
 
 /*
-- 
2.25.1


From 04e452890ada8390828aa4c5c87ceefe44daa50f Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 18 May 2022 16:56:01 +1200
Subject: [PATCH 84/99] CVE-2022-2031 s4:kdc: Fix canonicalisation of
 kadmin/changepw principal

Since this principal goes through the samba_kdc_fetch_server() path,
setting the canonicalisation flag would cause the principal to be
replaced with the sAMAccountName; this meant requests to
kadmin/changepw@REALM would result in a ticket to krbtgt@REALM. Now we
properly handle canonicalisation for the kadmin/changepw principal.

View with 'git show -b'.

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

Pair-Programmed-With: Andreas Schneider <asn@samba.org>
Signed-off-by: Andreas Schneider <asn@samba.org>
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Adapted entry to entry_ex->entry; removed MIT KDC
 1.20-specific knownfails]
---
 selftest/knownfail.d/kadmin_changepw |  1 -
 selftest/knownfail_heimdal_kdc       |  2 -
 source4/kdc/db-glue.c                | 84 +++++++++++++++-------------
 3 files changed, 46 insertions(+), 41 deletions(-)
 delete mode 100644 selftest/knownfail.d/kadmin_changepw

diff --git a/selftest/knownfail.d/kadmin_changepw b/selftest/knownfail.d/kadmin_changepw
deleted file mode 100644
index 97c14793ea5..00000000000
--- a/selftest/knownfail.d/kadmin_changepw
+++ /dev/null
@@ -1 +0,0 @@
-^samba4.blackbox.kpasswd.MIT kpasswd.change.user.password
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index ab7230060ab..6abbbf75391 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -112,8 +112,6 @@
 #
 # Kpasswd tests
 #
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 385c118a073..d2d7136608e 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -830,6 +830,7 @@ static krb5_error_code samba_kdc_get_entry_principal(
 		const char *samAccountName,
 		enum samba_kdc_ent_type ent_type,
 		unsigned flags,
+		bool is_kadmin_changepw,
 		krb5_const_principal in_princ,
 		krb5_principal *out_princ)
 {
@@ -849,46 +850,52 @@ static krb5_error_code samba_kdc_get_entry_principal(
 	 * fixed UPPER case realm, but the as-sent username
 	 */
 
-	if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT && canon) {
-		/*
-		 * When requested to do so, ensure that the
-		 * both realm values in the principal are set
-		 * to the upper case, canonical realm
-		 */
-		code = smb_krb5_make_principal(context,
-					       out_princ,
-					       lpcfg_realm(lp_ctx),
-					       "krbtgt",
-					       lpcfg_realm(lp_ctx),
-					       NULL);
-		if (code != 0) {
-			return code;
-		}
-		smb_krb5_principal_set_type(context,
-					    *out_princ,
-					    KRB5_NT_SRV_INST);
+	/*
+	 * We need to ensure that the kadmin/changepw principal isn't able to
+	 * issue krbtgt tickets, even if canonicalization is turned on.
+	 */
+	if (!is_kadmin_changepw) {
+		if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT && canon) {
+			/*
+			 * When requested to do so, ensure that the
+			 * both realm values in the principal are set
+			 * to the upper case, canonical realm
+			 */
+			code = smb_krb5_make_principal(context,
+						       out_princ,
+						       lpcfg_realm(lp_ctx),
+						       "krbtgt",
+						       lpcfg_realm(lp_ctx),
+						       NULL);
+			if (code != 0) {
+				return code;
+			}
+			smb_krb5_principal_set_type(context,
+						    *out_princ,
+						    KRB5_NT_SRV_INST);
 
-		return 0;
-	}
+			return 0;
+		}
 
-	if ((canon && flags & (SDB_F_FORCE_CANON|SDB_F_FOR_AS_REQ)) ||
-	    (ent_type == SAMBA_KDC_ENT_TYPE_ANY && in_princ == NULL)) {
-		/*
-		 * SDB_F_CANON maps from the canonicalize flag in the
-		 * packet, and has a different meaning between AS-REQ
-		 * and TGS-REQ.  We only change the principal in the
-		 * AS-REQ case.
-		 *
-		 * The SDB_F_FORCE_CANON if for new MIT KDC code that
-		 * wants the canonical name in all lookups, and takes
-		 * care to canonicalize only when appropriate.
-		 */
-		code = smb_krb5_make_principal(context,
-					      out_princ,
-					      lpcfg_realm(lp_ctx),
-					      samAccountName,
-					      NULL);
-		return code;
+		if ((canon && flags & (SDB_F_FORCE_CANON|SDB_F_FOR_AS_REQ)) ||
+		    (ent_type == SAMBA_KDC_ENT_TYPE_ANY && in_princ == NULL)) {
+			/*
+			 * SDB_F_CANON maps from the canonicalize flag in the
+			 * packet, and has a different meaning between AS-REQ
+			 * and TGS-REQ.  We only change the principal in the
+			 * AS-REQ case.
+			 *
+			 * The SDB_F_FORCE_CANON if for new MIT KDC code that
+			 * wants the canonical name in all lookups, and takes
+			 * care to canonicalize only when appropriate.
+			 */
+			code = smb_krb5_make_principal(context,
+						      out_princ,
+						      lpcfg_realm(lp_ctx),
+						      samAccountName,
+						      NULL);
+			return code;
+		}
 	}
 
 	/*
@@ -1194,6 +1201,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 					    samAccountName,
 					    ent_type,
 					    flags,
+					    entry_ex->entry.flags.change_pw,
 					    principal,
 					    &entry_ex->entry.principal);
 	if (ret != 0) {
-- 
2.25.1


From a46d0ac59f074f999217586f18ba8772a645b246 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 24 May 2022 17:53:49 +1200
Subject: [PATCH 85/99] CVE-2022-2031 s4:kdc: Limit kpasswd ticket lifetime to
 two minutes or less

This matches the behaviour of Windows.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Adapted entry to entry_ex->entry; included
 samba_kdc.h header file]
---
 selftest/knownfail_heimdal_kdc             | 1 -
 selftest/knownfail_mit_kdc                 | 1 -
 source4/kdc/db-glue.c                      | 5 +++++
 source4/kdc/mit-kdb/kdb_samba_principals.c | 2 +-
 source4/kdc/samba_kdc.h                    | 2 ++
 5 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 6abbbf75391..4fb838f0e11 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -113,7 +113,6 @@
 # Kpasswd tests
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 0389672e5d9..ed8f7069319 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -546,7 +546,6 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_lifetime.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index d2d7136608e..073ec83c8cf 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -1226,6 +1226,11 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
 					        kdc_db_ctx->policy.usr_tkt_lifetime);
 	}
 
+	if (entry_ex->entry.flags.change_pw) {
+		/* Limit lifetime of kpasswd tickets to two minutes or less. */
+		*entry_ex->entry.max_life = MIN(*entry_ex->entry.max_life, CHANGEPW_LIFETIME);
+	}
+
 	entry_ex->entry.max_renew = malloc(sizeof(*entry_ex->entry.max_life));
 	if (entry_ex->entry.max_renew == NULL) {
 		ret = ENOMEM;
diff --git a/source4/kdc/mit-kdb/kdb_samba_principals.c b/source4/kdc/mit-kdb/kdb_samba_principals.c
index 3917b9824c6..da21251179b 100644
--- a/source4/kdc/mit-kdb/kdb_samba_principals.c
+++ b/source4/kdc/mit-kdb/kdb_samba_principals.c
@@ -27,6 +27,7 @@
 #include <profile.h>
 #include <kdb.h>
 
+#include "kdc/samba_kdc.h"
 #include "kdc/mit_samba.h"
 #include "kdb_samba.h"
 
@@ -34,7 +35,6 @@
 #define DBGC_CLASS DBGC_KERBEROS
 
 #define ADMIN_LIFETIME 60*60*3 /* 3 hours */
-#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
 
 krb5_error_code ks_get_principal(krb5_context context,
 				 krb5_const_principal principal,
diff --git a/source4/kdc/samba_kdc.h b/source4/kdc/samba_kdc.h
index e228a82ce6a..8010d7c35ed 100644
--- a/source4/kdc/samba_kdc.h
+++ b/source4/kdc/samba_kdc.h
@@ -62,4 +62,6 @@ struct samba_kdc_entry {
 
 extern struct hdb_method hdb_samba4_interface;
 
+#define CHANGEPW_LIFETIME 60*2 /* 2 minutes */
+
 #endif /* _SAMBA_KDC_H_ */
-- 
2.25.1


From c7408dd944ee5a0de5f04079d158f4575fb9036a Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Mon, 30 May 2022 19:18:17 +1200
Subject: [PATCH 86/99] CVE-2022-2031 s4:kdc: Reject tickets during the last
 two minutes of their life

For Heimdal, this now matches the behaviour of Windows. The object of
this requirement is to ensure we don't allow kpasswd tickets, not having
a lifetime of more than two minutes, to be passed off as TGTs.

An existing requirement for TGTs to contain a REQUESTER_SID PAC buffer
suffices to prevent kpasswd ticket misuse, so this is just an additional
precaution on top.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org As we don't have access to the ticket or the request
 in the plugin, rewrote check directly in Heimdal KDC]
---
 selftest/knownfail_heimdal_kdc |  1 -
 source4/heimdal/kdc/krb5tgs.c  | 19 ++++++++++++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 4fb838f0e11..dfe04dd1448 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -113,7 +113,6 @@
 # Kpasswd tests
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index 38dba8493ae..15be136496f 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -33,6 +33,9 @@
 
 #include "kdc_locl.h"
 
+/* Awful hack to get access to 'struct samba_kdc_entry'. */
+#include "../../kdc/samba_kdc.h"
+
 /*
  * return the realm of a krbtgt-ticket or NULL
  */
@@ -130,6 +133,7 @@ check_PAC(krb5_context context,
 static krb5_error_code
 check_tgs_flags(krb5_context context,
 		krb5_kdc_configuration *config,
+		const hdb_entry_ex *krbtgt_in,
 		KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
 {
     KDCOptions f = b->kdc_options;
@@ -244,6 +248,17 @@ check_tgs_flags(krb5_context context,
 	    et->endtime = min(*et->renew_till, et->endtime);
     }
 
+    if (tgt->endtime - kdc_time <= CHANGEPW_LIFETIME) {
+	/* Check that the ticket has not arrived across a trust. */
+	const struct samba_kdc_entry *skdc_entry = krbtgt_in->ctx;
+	if (!skdc_entry->is_trust) {
+	    /* This may be a kpasswd ticket rather than a TGT, so don't accept it. */
+	    kdc_log(context, config, 0,
+		    "Ticket is not a ticket-granting ticket");
+	    return KRB5KRB_AP_ERR_TKT_EXPIRED;
+	}
+    }
+
 #if 0
     /* checks for excess flags */
     if(f.request_anonymous && !config->allow_anonymous){
@@ -510,6 +525,7 @@ tgs_make_reply(krb5_context context,
 	       hdb_entry_ex *client,
 	       krb5_principal client_principal,
                const char *tgt_realm,
+	       const hdb_entry_ex *krbtgt_in,
 	       hdb_entry_ex *krbtgt,
 	       krb5_pac mspac,
 	       uint16_t rodc_id,
@@ -538,7 +554,7 @@ tgs_make_reply(krb5_context context,
     ALLOC(et.starttime);
     *et.starttime = kdc_time;
 
-    ret = check_tgs_flags(context, config, b, tgt, &et);
+    ret = check_tgs_flags(context, config, krbtgt_in, b, tgt, &et);
     if(ret)
 	goto out;
 
@@ -2129,6 +2145,7 @@ server_lookup:
 			 client,
 			 cp,
 			 tgt_realm,
+			 krbtgt,
 			 krbtgt_out,
 			 mspac,
 			 rodc_id,
-- 
2.25.1


From 389a5523485dfbd48e87b6ee9c39c6c2e16294a0 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Tue, 14 Jun 2022 15:23:55 +1200
Subject: [PATCH 87/99] CVE-2022-2031 tests/krb5: Test truncated forms of
 server principals

We should not be able to use krb@REALM instead of krbtgt@REALM.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed conflicts due to having older version of
 _run_as_req_enc_timestamp()]
---
 python/samba/tests/krb5/as_req_tests.py | 40 ++++++++++++++++++++++---
 selftest/knownfail_heimdal_kdc          |  4 +++
 selftest/knownfail_mit_kdc              |  4 +++
 3 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/python/samba/tests/krb5/as_req_tests.py b/python/samba/tests/krb5/as_req_tests.py
index 315720f85d6..054a49b64aa 100755
--- a/python/samba/tests/krb5/as_req_tests.py
+++ b/python/samba/tests/krb5/as_req_tests.py
@@ -27,6 +27,7 @@ from samba.tests.krb5.kdc_base_test import KDCBaseTest
 import samba.tests.krb5.kcrypto as kcrypto
 import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
 from samba.tests.krb5.rfc4120_constants import (
+    KDC_ERR_S_PRINCIPAL_UNKNOWN,
     KDC_ERR_ETYPE_NOSUPP,
     KDC_ERR_PREAUTH_REQUIRED,
     KU_PA_ENC_TIMESTAMP,
@@ -40,7 +41,8 @@ global_hexdump = False
 
 
 class AsReqBaseTest(KDCBaseTest):
-    def _run_as_req_enc_timestamp(self, client_creds):
+    def _run_as_req_enc_timestamp(self, client_creds, sname=None,
+                                  expected_error=None):
         client_account = client_creds.get_username()
         client_as_etypes = self.get_default_enctypes()
         client_kvno = client_creds.get_kvno()
@@ -50,8 +52,9 @@ class AsReqBaseTest(KDCBaseTest):
 
         cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
                                           names=[client_account])
-        sname = self.PrincipalName_create(name_type=NT_SRV_INST,
-                                          names=[krbtgt_account, realm])
+        if sname is None:
+            sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+                                              names=[krbtgt_account, realm])
 
         expected_crealm = realm
         expected_cname = cname
@@ -63,7 +66,10 @@ class AsReqBaseTest(KDCBaseTest):
 
         initial_etypes = client_as_etypes
         initial_kdc_options = krb5_asn1.KDCOptions('forwardable')
-        initial_error_mode = KDC_ERR_PREAUTH_REQUIRED
+        if expected_error is not None:
+            initial_error_mode = expected_error
+        else:
+            initial_error_mode = KDC_ERR_PREAUTH_REQUIRED
 
         rep, kdc_exchange_dict = self._test_as_exchange(cname,
                                                         realm,
@@ -80,6 +86,10 @@ class AsReqBaseTest(KDCBaseTest):
                                                         None,
                                                         initial_kdc_options,
                                                         pac_request=True)
+
+        if expected_error is not None:
+            return None
+
         etype_info2 = kdc_exchange_dict['preauth_etype_info2']
         self.assertIsNotNone(etype_info2)
 
@@ -209,6 +219,28 @@ class AsReqKerberosTests(AsReqBaseTest):
         client_creds = self.get_mach_creds()
         self._run_as_req_enc_timestamp(client_creds)
 
+    # Ensure we can't use truncated well-known principals such as krb@REALM
+    # instead of krbtgt@REALM.
+    def test_krbtgt_wrong_principal(self):
+        client_creds = self.get_client_creds()
+
+        krbtgt_creds = self.get_krbtgt_creds()
+
+        krbtgt_account = krbtgt_creds.get_username()
+        realm = krbtgt_creds.get_realm()
+
+        # Truncate the name of the krbtgt principal.
+        krbtgt_account = krbtgt_account[:3]
+
+        wrong_krbtgt_princ = self.PrincipalName_create(
+            name_type=NT_SRV_INST,
+            names=[krbtgt_account, realm])
+
+        self._run_as_req_enc_timestamp(
+            client_creds,
+            sname=wrong_krbtgt_princ,
+            expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN)
+
 
 if __name__ == "__main__":
     global_asn1_print = False
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index dfe04dd1448..7ad9ee85778 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -116,3 +116,7 @@
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
+#
+# AS-REQ tests
+#
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_krbtgt_wrong_principal\(
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index ed8f7069319..ad0fa84aedb 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -549,3 +549,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
+#
+# AS-REQ tests
+#
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_krbtgt_wrong_principal\(
-- 
2.25.1


From 959ed604ee1588f9a92c269a014fbf12b72fb8a4 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 25 May 2022 20:00:55 +1200
Subject: [PATCH 88/99] CVE-2022-2031 s4:kdc: Don't use strncmp to compare
 principal components

We would only compare the first 'n' characters, where 'n' is the length
of the principal component string, so 'k@REALM' would erroneously be
considered equal to 'krbtgt@REALM'.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 selftest/knownfail_heimdal_kdc |  4 ----
 selftest/knownfail_mit_kdc     |  4 ----
 source4/kdc/db-glue.c          | 27 ++++++++++++++++++++++-----
 3 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 7ad9ee85778..dfe04dd1448 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -116,7 +116,3 @@
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
-#
-# AS-REQ tests
-#
-^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_krbtgt_wrong_principal\(
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index ad0fa84aedb..ed8f7069319 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -549,7 +549,3 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
-#
-# AS-REQ tests
-#
-^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_krbtgt_wrong_principal\(
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 073ec83c8cf..cfa2097acbd 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -769,15 +769,19 @@ static int principal_comp_strcmp_int(krb5_context context,
 				     bool do_strcasecmp)
 {
 	const char *p;
-	size_t len;
 
 #if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
 	p = krb5_principal_get_comp_string(context, principal, component);
 	if (p == NULL) {
 		return -1;
 	}
-	len = strlen(p);
+	if (do_strcasecmp) {
+		return strcasecmp(p, string);
+	} else {
+		return strcmp(p, string);
+	}
 #else
+	size_t len;
 	krb5_data *d;
 	if (component >= krb5_princ_size(context, principal)) {
 		return -1;
@@ -789,13 +793,26 @@ static int principal_comp_strcmp_int(krb5_context context,
 	}
 
 	p = d->data;
-	len = d->length;
-#endif
+
+	len = strlen(string);
+
+	/*
+	 * We explicitly return -1 or 1. Subtracting of the two lengths might
+	 * give the wrong result if the result overflows or loses data when
+	 * narrowed to int.
+	 */
+	if (d->length < len) {
+		return -1;
+	} else if (d->length > len) {
+		return 1;
+	}
+
 	if (do_strcasecmp) {
 		return strncasecmp(p, string, len);
 	} else {
-		return strncmp(p, string, len);
+		return memcmp(p, string, len);
 	}
+#endif
 }
 
 static int principal_comp_strcasecmp(krb5_context context,
-- 
2.25.1


From 4b0304ab670a5dc3819f93633c190f722e3906d7 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 26 May 2022 16:36:30 +1200
Subject: [PATCH 89/99] CVE-2022-32744 s4:kdc: Rename keytab_name ->
 kpasswd_keytab_name

This makes explicitly clear the purpose of this keytab.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed conflicts due to lacking HDBGET support]
---
 source4/kdc/kdc-heimdal.c     | 4 ++--
 source4/kdc/kdc-server.h      | 2 +-
 source4/kdc/kdc-service-mit.c | 4 ++--
 source4/kdc/kpasswd-service.c | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
index ce32d3cb1b3..ca202bd6f9d 100644
--- a/source4/kdc/kdc-heimdal.c
+++ b/source4/kdc/kdc-heimdal.c
@@ -444,8 +444,8 @@ static void kdc_post_fork(struct task_server *task, struct process_details *pd)
 		return;
 	}
 
-	kdc->keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx);
-	if (kdc->keytab_name == NULL) {
+	kdc->kpasswd_keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx);
+	if (kdc->kpasswd_keytab_name == NULL) {
 		task_server_terminate(task,
 				      "kdc: Failed to set keytab name",
 				      true);
diff --git a/source4/kdc/kdc-server.h b/source4/kdc/kdc-server.h
index fd883c2e4b4..89b30f122f5 100644
--- a/source4/kdc/kdc-server.h
+++ b/source4/kdc/kdc-server.h
@@ -40,7 +40,7 @@ struct kdc_server {
 	struct ldb_context *samdb;
 	bool am_rodc;
 	uint32_t proxy_timeout;
-	const char *keytab_name;
+	const char *kpasswd_keytab_name;
 	void *private_data;
 };
 
diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
index 5d4180aa7cc..22663b6ecc8 100644
--- a/source4/kdc/kdc-service-mit.c
+++ b/source4/kdc/kdc-service-mit.c
@@ -291,8 +291,8 @@ NTSTATUS mitkdc_task_init(struct task_server *task)
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	kdc->keytab_name = talloc_asprintf(kdc, "KDB:");
-	if (kdc->keytab_name == NULL) {
+	kdc->kpasswd_keytab_name = talloc_asprintf(kdc, "KDB:");
+	if (kdc->kpasswd_keytab_name == NULL) {
 		task_server_terminate(task,
 				      "KDC: Out of memory",
 				      true);
diff --git a/source4/kdc/kpasswd-service.c b/source4/kdc/kpasswd-service.c
index 379ddebf3ad..aec30850173 100644
--- a/source4/kdc/kpasswd-service.c
+++ b/source4/kdc/kpasswd-service.c
@@ -170,7 +170,7 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
 
 	rv = cli_credentials_set_keytab_name(server_credentials,
 					     kdc->task->lp_ctx,
-					     kdc->keytab_name,
+					     kdc->kpasswd_keytab_name,
 					     CRED_SPECIFIED);
 	if (rv != 0) {
 		DBG_ERR("Failed to set credentials keytab name\n");
-- 
2.25.1


From faa0a83813d7e24016381da5a4b8c7f664d95acc Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 8 Jun 2022 13:53:29 +1200
Subject: [PATCH 90/99] s4:kdc: Remove kadmin mode from HDB plugin

It appears we no longer require it.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/kdc/hdb-samba4-plugin.c | 35 +++++++--------------------------
 1 file changed, 7 insertions(+), 28 deletions(-)

diff --git a/source4/kdc/hdb-samba4-plugin.c b/source4/kdc/hdb-samba4-plugin.c
index 6f76124995d..4b90a766f76 100644
--- a/source4/kdc/hdb-samba4-plugin.c
+++ b/source4/kdc/hdb-samba4-plugin.c
@@ -21,40 +21,20 @@
 
 #include "includes.h"
 #include "kdc/kdc-glue.h"
-#include "kdc/db-glue.h"
-#include "lib/util/samba_util.h"
 #include "lib/param/param.h"
-#include "source4/lib/events/events.h"
 
 static krb5_error_code hdb_samba4_create(krb5_context context, struct HDB **db, const char *arg)
 {
 	NTSTATUS nt_status;
-	void *ptr;
-	struct samba_kdc_base_context *base_ctx;
-	
-	if (sscanf(arg, "&%p", &ptr) == 1) {
-		base_ctx = talloc_get_type_abort(ptr, struct samba_kdc_base_context);
-	} else if (arg[0] == '\0' || file_exist(arg)) {
-		/* This mode for use in kadmin, rather than in Samba */
-		
-		setup_logging("hdb_samba4", DEBUG_DEFAULT_STDERR);
-
-		base_ctx = talloc_zero(NULL, struct samba_kdc_base_context);
-		if (!base_ctx) {
-			return ENOMEM;
-		}
-
-		base_ctx->ev_ctx = s4_event_context_init(base_ctx);
-		base_ctx->lp_ctx = loadparm_init_global(false);
-		if (arg[0]) {
-			lpcfg_load(base_ctx->lp_ctx, arg);
-		} else {
-			lpcfg_load_default(base_ctx->lp_ctx);
-		}
-	} else {
+	void *ptr = NULL;
+	struct samba_kdc_base_context *base_ctx = NULL;
+
+	if (sscanf(arg, "&%p", &ptr) != 1) {
 		return EINVAL;
 	}
 
+	base_ctx = talloc_get_type_abort(ptr, struct samba_kdc_base_context);
+
 	/* The global kdc_mem_ctx and kdc_lp_ctx, Disgusting, ugly hack, but it means one less private hook */
 	nt_status = hdb_samba4_create_kdc(base_ctx, context, db);
 
@@ -90,8 +70,7 @@ static void hdb_samba4_fini(void *ctx)
 
 /* Only used in the hdb-backed keytab code
  * for a keytab of 'samba4&<address>' or samba4, to find
- * kpasswd's key in the main DB, and to
- * copy all the keys into a file (libnet_keytab_export)
+ * kpasswd's key in the main DB
  *
  * The <address> is the string form of a pointer to a talloced struct hdb_samba_context
  */
-- 
2.25.1


From e21efbabccbf9c422347e9e94b3f217186556ee7 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 26 May 2022 16:39:20 +1200
Subject: [PATCH 91/99] CVE-2022-32744 s4:kdc: Modify HDB plugin to only look
 up kpasswd principal

This plugin is now only used by the kpasswd service. Thus, ensuring we
only look up the kadmin/changepw principal means we can't be fooled into
accepting tickets for other service principals. We make sure not to
specify a specific kvno, to ensure that we do not accept RODC-issued
tickets.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed knownfail conflicts]

[jsutton@samba.org Renamed entry to entry_ex; fixed knownfail conflicts;
 retained knownfail for test_kpasswd_from_rodc which now causes the KDC
 to panic]
---
 selftest/knownfail_heimdal_kdc  |  3 --
 source4/kdc/hdb-samba4-plugin.c |  2 +-
 source4/kdc/hdb-samba4.c        | 66 +++++++++++++++++++++++++++++++++
 source4/kdc/kdc-glue.h          |  3 ++
 4 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index dfe04dd1448..1b5063d2630 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -113,6 +113,3 @@
 # Kpasswd tests
 #
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/source4/kdc/hdb-samba4-plugin.c b/source4/kdc/hdb-samba4-plugin.c
index 4b90a766f76..dba25e825de 100644
--- a/source4/kdc/hdb-samba4-plugin.c
+++ b/source4/kdc/hdb-samba4-plugin.c
@@ -36,7 +36,7 @@ static krb5_error_code hdb_samba4_create(krb5_context context, struct HDB **db,
 	base_ctx = talloc_get_type_abort(ptr, struct samba_kdc_base_context);
 
 	/* The global kdc_mem_ctx and kdc_lp_ctx, Disgusting, ugly hack, but it means one less private hook */
-	nt_status = hdb_samba4_create_kdc(base_ctx, context, db);
+	nt_status = hdb_samba4_kpasswd_create_kdc(base_ctx, context, db);
 
 	if (NT_STATUS_IS_OK(nt_status)) {
 		return 0;
diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c
index 43e836f8360..a8aae50b5b0 100644
--- a/source4/kdc/hdb-samba4.c
+++ b/source4/kdc/hdb-samba4.c
@@ -136,6 +136,47 @@ static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db,
 	return code;
 }
 
+static krb5_error_code hdb_samba4_kpasswd_fetch_kvno(krb5_context context, HDB *db,
+						     krb5_const_principal _principal,
+						     unsigned flags,
+						     krb5_kvno _kvno,
+						     hdb_entry_ex *entry_ex)
+{
+	struct samba_kdc_db_context *kdc_db_ctx = NULL;
+	krb5_error_code ret;
+	krb5_principal kpasswd_principal = NULL;
+
+	kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
+					   struct samba_kdc_db_context);
+
+	ret = smb_krb5_make_principal(context, &kpasswd_principal,
+				      lpcfg_realm(kdc_db_ctx->lp_ctx),
+				      "kadmin", "changepw",
+				      NULL);
+	if (ret) {
+		return ret;
+	}
+	smb_krb5_principal_set_type(context, kpasswd_principal, KRB5_NT_SRV_INST);
+
+	/*
+	 * For the kpasswd service, always ensure we get the latest kvno. This
+	 * also means we (correctly) refuse RODC-issued tickets.
+	 */
+	flags &= ~HDB_F_KVNO_SPECIFIED;
+
+	/* Don't bother looking up a client or krbtgt. */
+	flags &= ~(SDB_F_GET_CLIENT|SDB_F_GET_KRBTGT);
+
+	ret = hdb_samba4_fetch_kvno(context, db,
+				    kpasswd_principal,
+				    flags,
+				    0,
+				    entry_ex);
+
+	krb5_free_principal(context, kpasswd_principal);
+	return ret;
+}
+
 static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsigned flags,
 					hdb_entry_ex *entry)
 {
@@ -194,6 +235,14 @@ static krb5_error_code hdb_samba4_nextkey(krb5_context context, HDB *db, unsigne
 	return ret;
 }
 
+static krb5_error_code hdb_samba4_nextkey_panic(krb5_context context, HDB *db,
+						unsigned flags,
+						hdb_entry_ex *entry)
+{
+	DBG_ERR("Attempt to iterate kpasswd keytab => PANIC\n");
+	smb_panic("hdb_samba4_nextkey_panic: Attempt to iterate kpasswd keytab");
+}
+
 static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db)
 {
 	talloc_free(db);
@@ -522,3 +571,20 @@ NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx,
 
 	return NT_STATUS_OK;
 }
+
+NTSTATUS hdb_samba4_kpasswd_create_kdc(struct samba_kdc_base_context *base_ctx,
+				       krb5_context context, struct HDB **db)
+{
+	NTSTATUS nt_status;
+
+	nt_status = hdb_samba4_create_kdc(base_ctx, context, db);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		return nt_status;
+	}
+
+	(*db)->hdb_fetch_kvno = hdb_samba4_kpasswd_fetch_kvno;
+	(*db)->hdb_firstkey = hdb_samba4_nextkey_panic;
+	(*db)->hdb_nextkey = hdb_samba4_nextkey_panic;
+
+	return NT_STATUS_OK;
+}
diff --git a/source4/kdc/kdc-glue.h b/source4/kdc/kdc-glue.h
index c083b8c6429..ff8684e1666 100644
--- a/source4/kdc/kdc-glue.h
+++ b/source4/kdc/kdc-glue.h
@@ -45,6 +45,9 @@ kdc_code kpasswdd_process(struct kdc_server *kdc,
 NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx,
 			       krb5_context context, struct HDB **db);
 
+NTSTATUS hdb_samba4_kpasswd_create_kdc(struct samba_kdc_base_context *base_ctx,
+				       krb5_context context, struct HDB **db);
+
 /* from kdc-glue.c */
 int kdc_check_pac(krb5_context krb5_context,
 		  DATA_BLOB server_sig,
-- 
2.25.1


From b64e1b4a510c81628feeb68af75afd3275ea75c3 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Mon, 30 May 2022 19:16:02 +1200
Subject: [PATCH 92/99] CVE-2022-32744 s4:kpasswd: Ensure we pass the kpasswd
 server principal into krb5_rd_req_ctx()

To ensure that, when decrypting the kpasswd ticket, we look up the
correct principal and don't trust the sname from the ticket, we should
pass the principal name of the kpasswd service into krb5_rd_req_ctx().
However, gensec_krb5_update_internal() will pass in NULL unless the
principal in our credentials is CRED_SPECIFIED.

At present, our principal will be considered obtained as CRED_SMB_CONF
(from the cli_credentials_set_conf() a few lines up), so we explicitly
set the realm again, but this time as CRED_SPECIFIED. Now the value of
server_in_keytab that we provide to smb_krb5_rd_req_decoded() will not
be NULL.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Removed knownfail as KDC no longer panics]
---
 selftest/knownfail_heimdal_kdc |  4 ----
 selftest/knownfail_mit_kdc     |  2 --
 source4/kdc/kpasswd-service.c  | 30 ++++++++++++++++++++++++++++++
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 1b5063d2630..692b9ecdd72 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -109,7 +109,3 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-#
-# Kpasswd tests
-#
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index ed8f7069319..6cad47701ae 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -547,5 +547,3 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
diff --git a/source4/kdc/kpasswd-service.c b/source4/kdc/kpasswd-service.c
index aec30850173..d2f1bb02906 100644
--- a/source4/kdc/kpasswd-service.c
+++ b/source4/kdc/kpasswd-service.c
@@ -29,6 +29,7 @@
 #include "kdc/kdc-server.h"
 #include "kdc/kpasswd-service.h"
 #include "kdc/kpasswd-helper.h"
+#include "param/param.h"
 
 #define HEADER_LEN 6
 #ifndef RFC3244_VERSION
@@ -161,6 +162,20 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
 		goto done;
 	}
 
+	/*
+	 * After calling cli_credentials_set_conf(), explicitly set the realm
+	 * with CRED_SPECIFIED. We need to do this so the result of
+	 * principal_from_credentials() called from the gensec layer is
+	 * CRED_SPECIFIED rather than CRED_SMB_CONF, avoiding a fallback to
+	 * match-by-key (very undesirable in this case).
+	 */
+	ok = cli_credentials_set_realm(server_credentials,
+				       lpcfg_realm(kdc->task->lp_ctx),
+				       CRED_SPECIFIED);
+	if (!ok) {
+		goto done;
+	}
+
 	ok = cli_credentials_set_username(server_credentials,
 					  "kadmin/changepw",
 					  CRED_SPECIFIED);
@@ -168,6 +183,21 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
 		goto done;
 	}
 
+	/* Check that the server principal is indeed CRED_SPECIFIED. */
+	{
+		char *principal = NULL;
+		enum credentials_obtained obtained;
+
+		principal = cli_credentials_get_principal_and_obtained(server_credentials,
+								       tmp_ctx,
+								       &obtained);
+		if (obtained < CRED_SPECIFIED) {
+			goto done;
+		}
+
+		TALLOC_FREE(principal);
+	}
+
 	rv = cli_credentials_set_keytab_name(server_credentials,
 					     kdc->task->lp_ctx,
 					     kdc->kpasswd_keytab_name,
-- 
2.25.1


From 22bd1bc2d7308167ea316c6b48f130d378ab4c8b Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 10 Jun 2022 19:17:11 +1200
Subject: [PATCH 93/99] CVE-2022-2031 tests/krb5: Add test that we cannot
 provide a TGT to kpasswd

The kpasswd service should require a kpasswd service ticket, and
disallow TGTs.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed knownfail conflicts]

[jsutton@samba.org Fixed knownfail conflicts]
---
 python/samba/tests/krb5/kpasswd_tests.py | 28 ++++++++++++++++++++++++
 selftest/knownfail_heimdal_kdc           |  4 ++++
 selftest/knownfail_mit_kdc               |  4 ++++
 3 files changed, 36 insertions(+)

diff --git a/python/samba/tests/krb5/kpasswd_tests.py b/python/samba/tests/krb5/kpasswd_tests.py
index 3a6c7d818dc..0db857f7bbd 100755
--- a/python/samba/tests/krb5/kpasswd_tests.py
+++ b/python/samba/tests/krb5/kpasswd_tests.py
@@ -31,6 +31,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KDC_ERR_TGT_REVOKED,
     KDC_ERR_TKT_EXPIRED,
     KPASSWD_ACCESSDENIED,
+    KPASSWD_AUTHERROR,
     KPASSWD_HARDERROR,
     KPASSWD_INITIAL_FLAG_NEEDED,
     KPASSWD_MALFORMED,
@@ -779,6 +780,33 @@ class KpasswdTests(KDCBaseTest):
         self._make_tgs_request(creds, service_creds, ticket,
                                expect_error=False)
 
+    # Show that we cannot provide a TGT to kpasswd to change the password.
+    def test_kpasswd_tgt(self):
+        # Create an account for testing, and get a TGT.
+        creds = self._get_creds()
+        tgt = self.get_tgt(creds)
+
+        # Change the sname of the ticket to match that of kadmin/changepw.
+        tgt.set_sname(self.get_kpasswd_sname())
+
+        expected_code = KPASSWD_AUTHERROR
+        expected_msg = b'A TGT may not be used as a ticket to kpasswd'
+
+        # Set the password.
+        new_password = generate_random_password(32, 32)
+        self.kpasswd_exchange(tgt,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.SET)
+
+        # Change the password.
+        self.kpasswd_exchange(tgt,
+                              new_password,
+                              expected_code,
+                              expected_msg,
+                              mode=self.KpasswdMode.CHANGE)
+
     # Test that kpasswd rejects requests with a service ticket.
     def test_kpasswd_non_initial(self):
         # Create an account for testing, and get a TGT.
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 692b9ecdd72..7b439478eca 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -109,3 +109,7 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
+#
+# Kpasswd tests
+#
+^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_tgt.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 6cad47701ae..7e0cdd9a3b7 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -547,3 +547,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
+#
+# Kpasswd tests
+#
+samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_tgt.ad_dc
-- 
2.25.1


From be9945a4d8e774e8255dd9ae0ed29c9a953ce3ff Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 10 Jun 2022 19:18:07 +1200
Subject: [PATCH 94/99] CVE-2022-2031 auth: Add ticket type field to
 auth_user_info_dc and auth_session_info

This field may be used to convey whether we were provided with a TGT or
a non-TGT. We ensure both structures are zeroed out to avoid incorrect
results being produced by an uninitialised field.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 auth/auth_sam_reply.c              |  2 +-
 auth/auth_util.c                   |  2 +-
 librpc/idl/auth.idl                | 23 +++++++++++++++++++++++
 source4/auth/ntlm/auth_developer.c |  2 +-
 source4/auth/sam.c                 |  2 +-
 source4/auth/session.c             |  2 ++
 source4/auth/system_session.c      |  6 +++---
 7 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/auth/auth_sam_reply.c b/auth/auth_sam_reply.c
index b5b6362dc93..2e27e5715d1 100644
--- a/auth/auth_sam_reply.c
+++ b/auth/auth_sam_reply.c
@@ -416,7 +416,7 @@ NTSTATUS make_user_info_dc_netlogon_validation(TALLOC_CTX *mem_ctx,
 		return NT_STATUS_INVALID_LEVEL;
 	}
 
-	user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
+	user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
 
 	/*
diff --git a/auth/auth_util.c b/auth/auth_util.c
index fe01babd107..ec9094d0f15 100644
--- a/auth/auth_util.c
+++ b/auth/auth_util.c
@@ -44,7 +44,7 @@ struct auth_session_info *copy_session_info(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	dst = talloc(mem_ctx, struct auth_session_info);
+	dst = talloc_zero(mem_ctx, struct auth_session_info);
 	if (dst == NULL) {
 		DBG_ERR("talloc failed\n");
 		TALLOC_FREE(frame);
diff --git a/librpc/idl/auth.idl b/librpc/idl/auth.idl
index 7de3d4c6bfb..59ed2c3c5ea 100644
--- a/librpc/idl/auth.idl
+++ b/librpc/idl/auth.idl
@@ -75,6 +75,26 @@ interface auth
 		[unique,charset(UTF8),string] char *sanitized_username;
 	} auth_user_info_unix;
 
+	/*
+	 * If the user was authenticated with a Kerberos ticket, this indicates
+	 * the type of the ticket; TGT, or non-TGT (i.e. service ticket). If
+	 * unset, the type is unknown. This indicator is useful for the KDC and
+	 * the kpasswd service, which share the same account and keys. By
+	 * ensuring it is provided with the appopriate ticket type, each service
+	 * avoids accepting a ticket meant for the other.
+	 *
+	 * The heuristic used to determine the type is the presence or absence
+	 * of a REQUESTER_SID buffer in the PAC; we use its presence to assume
+	 * we have a TGT. This heuristic will fail for older Samba versions and
+	 * Windows prior to Nov. 2021 updates, which lack support for this
+	 * buffer.
+	 */
+	typedef enum {
+		TICKET_TYPE_UNKNOWN = 0,
+		TICKET_TYPE_TGT = 1,
+		TICKET_TYPE_NON_TGT = 2
+	} ticket_type;
+
 	/* This is the interim product of the auth subsystem, before
 	 * privileges and local groups are handled */
 	typedef [public] struct {
@@ -83,6 +103,7 @@ interface auth
 		auth_user_info *info;
 		[noprint] DATA_BLOB user_session_key;
 		[noprint] DATA_BLOB lm_session_key;
+		ticket_type ticket_type;
 	} auth_user_info_dc;
 
 	typedef [public] struct {
@@ -112,6 +133,8 @@ interface auth
 		 * We generate this in auth_generate_session_info()
 		 */
 	        GUID unique_session_token;
+
+		ticket_type ticket_type;
 	} auth_session_info;
 
 	typedef [public] struct {
diff --git a/source4/auth/ntlm/auth_developer.c b/source4/auth/ntlm/auth_developer.c
index 1823989c68d..6e92252d5c5 100644
--- a/source4/auth/ntlm/auth_developer.c
+++ b/source4/auth/ntlm/auth_developer.c
@@ -76,7 +76,7 @@ static NTSTATUS name_to_ntstatus_check_password(struct auth_method_context *ctx,
 	}
 	NT_STATUS_NOT_OK_RETURN(nt_status);
 
-	user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
+	user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
 
 	/* This returns a pointer to a struct dom_sid, which is the
diff --git a/source4/auth/sam.c b/source4/auth/sam.c
index 8b233bab3ad..7c609655fcb 100644
--- a/source4/auth/sam.c
+++ b/source4/auth/sam.c
@@ -363,7 +363,7 @@ _PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx,
 	TALLOC_CTX *tmp_ctx;
 	struct ldb_message_element *el;
 
-	user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
+	user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
 
 	tmp_ctx = talloc_new(user_info_dc);
diff --git a/source4/auth/session.c b/source4/auth/session.c
index 8cf8670d848..34ad557eebb 100644
--- a/source4/auth/session.c
+++ b/source4/auth/session.c
@@ -222,6 +222,8 @@ _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
 
 	session_info->credentials = NULL;
 
+	session_info->ticket_type = user_info_dc->ticket_type;
+
 	talloc_steal(mem_ctx, session_info);
 	*_session_info = session_info;
 	talloc_free(tmp_ctx);
diff --git a/source4/auth/system_session.c b/source4/auth/system_session.c
index e46b4584817..17cfc4bab8b 100644
--- a/source4/auth/system_session.c
+++ b/source4/auth/system_session.c
@@ -119,7 +119,7 @@ NTSTATUS auth_system_user_info_dc(TALLOC_CTX *mem_ctx, const char *netbios_name,
 	struct auth_user_info_dc *user_info_dc;
 	struct auth_user_info *info;
 
-	user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
+	user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
 
 	/* This returns a pointer to a struct dom_sid, which is the
@@ -195,7 +195,7 @@ static NTSTATUS auth_domain_admin_user_info_dc(TALLOC_CTX *mem_ctx,
 	struct auth_user_info_dc *user_info_dc;
 	struct auth_user_info *info;
 
-	user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
+	user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
 
 	user_info_dc->num_sids = 7;
@@ -364,7 +364,7 @@ _PUBLIC_ NTSTATUS auth_anonymous_user_info_dc(TALLOC_CTX *mem_ctx,
 {
 	struct auth_user_info_dc *user_info_dc;
 	struct auth_user_info *info;
-	user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
+	user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
 
 	/* This returns a pointer to a struct dom_sid, which is the
-- 
2.25.1


From b7e3cb83005ef28c70dc8d64cd0a57ba80ae9f4e Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 10 Jun 2022 19:18:35 +1200
Subject: [PATCH 95/99] CVE-2022-2031 s4:auth: Use PAC to determine whether
 ticket is a TGT

We use the presence or absence of a REQUESTER_SID PAC buffer to
determine whether the ticket is a TGT. We will later use this to reject
TGTs where a service ticket is expected.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source4/auth/kerberos/kerberos_pac.c | 44 ++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c
index 54ef4d61b02..bd0ae20e007 100644
--- a/source4/auth/kerberos/kerberos_pac.c
+++ b/source4/auth/kerberos/kerberos_pac.c
@@ -282,6 +282,28 @@
 	return ret;
 }
 
+static krb5_error_code kerberos_pac_buffer_present(krb5_context context,
+						   const krb5_pac pac,
+						   uint32_t type)
+{
+#ifdef SAMBA4_USES_HEIMDAL
+	return krb5_pac_get_buffer(context, pac, type, NULL);
+#else /* MIT */
+	krb5_error_code ret;
+	krb5_data data;
+
+	/*
+	 * MIT won't let us pass NULL for the data parameter, so we are forced
+	 * to allocate a new buffer and then immediately free it.
+	 */
+	ret = krb5_pac_get_buffer(context, pac, type, &data);
+	if (ret == 0) {
+		krb5_free_data_contents(context, &data);
+	}
+	return ret;
+#endif /* SAMBA4_USES_HEIMDAL */
+}
+
 krb5_error_code kerberos_pac_to_user_info_dc(TALLOC_CTX *mem_ctx,
 					     krb5_pac pac,
 					     krb5_context context,
@@ -414,6 +436,28 @@ krb5_error_code kerberos_pac_to_user_info_dc(TALLOC_CTX *mem_ctx,
 			return EINVAL;
 		}
 	}
+
+	/*
+	 * Based on the presence of a REQUESTER_SID PAC buffer, ascertain
+	 * whether the ticket is a TGT. This helps the KDC and kpasswd service
+	 * ensure they do not accept tickets meant for the other.
+	 *
+	 * This heuristic will fail for older Samba versions and Windows prior
+	 * to Nov. 2021 updates, which lack support for the REQUESTER_SID PAC
+	 * buffer.
+	 */
+	ret = kerberos_pac_buffer_present(context, pac, PAC_TYPE_REQUESTER_SID);
+	if (ret == ENOENT) {
+		/* This probably isn't a TGT. */
+		user_info_dc_out->ticket_type = TICKET_TYPE_NON_TGT;
+	} else if (ret != 0) {
+		talloc_free(tmp_ctx);
+		return ret;
+	} else {
+		/* This probably is a TGT. */
+		user_info_dc_out->ticket_type = TICKET_TYPE_TGT;
+	}
+
 	*user_info_dc = user_info_dc_out;
 
 	return 0;
-- 
2.25.1


From 63d353e7b5ef235a86bf6df595951dc831108234 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Fri, 10 Jun 2022 19:18:53 +1200
Subject: [PATCH 96/99] CVE-2022-2031 s4:kpasswd: Do not accept TGTs as kpasswd
 tickets

If TGTs can be used as kpasswd tickets, the two-minute lifetime of a
authentic kpasswd ticket may be bypassed. Furthermore, kpasswd tickets
are not supposed to be cached, but using this flaw, a stolen credentials
cache containing a TGT may be used to change that account's password,
and thus is made more valuable to an attacker.

Since all TGTs should be issued with a REQUESTER_SID PAC buffer, and
service tickets without it, we assert the absence of this buffer to
ensure we're not accepting a TGT.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>

[jsutton@samba.org Fixed knownfail conflicts]

[jsutton@samba.org Fixed knownfail conflicts]
---
 selftest/knownfail_heimdal_kdc        |  4 ----
 selftest/knownfail_mit_kdc            |  4 ----
 source4/kdc/kpasswd-helper.c          | 20 ++++++++++++++++++++
 source4/kdc/kpasswd-helper.h          |  2 ++
 source4/kdc/kpasswd-service-heimdal.c | 13 +++++++++++++
 source4/kdc/kpasswd-service-mit.c     | 13 +++++++++++++
 6 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 7b439478eca..692b9ecdd72 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -109,7 +109,3 @@
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-#
-# Kpasswd tests
-#
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_tgt.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 7e0cdd9a3b7..6cad47701ae 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -547,7 +547,3 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
-#
-# Kpasswd tests
-#
-samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_tgt.ad_dc
diff --git a/source4/kdc/kpasswd-helper.c b/source4/kdc/kpasswd-helper.c
index 55a2f5b3bf6..2ffdb79aea5 100644
--- a/source4/kdc/kpasswd-helper.c
+++ b/source4/kdc/kpasswd-helper.c
@@ -241,3 +241,23 @@ NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
 
 	return status;
 }
+
+krb5_error_code kpasswd_check_non_tgt(struct auth_session_info *session_info,
+				      const char **error_string)
+{
+	switch(session_info->ticket_type) {
+	case TICKET_TYPE_TGT:
+		/* TGTs are disallowed here. */
+		*error_string = "A TGT may not be used as a ticket to kpasswd";
+		return KRB5_KPASSWD_AUTHERROR;
+	case TICKET_TYPE_NON_TGT:
+		/* Non-TGTs are permitted, and expected. */
+		break;
+	default:
+		/* In case we forgot to set the type. */
+		*error_string = "Failed to ascertain that ticket to kpasswd is not a TGT";
+		return KRB5_KPASSWD_HARDERROR;
+	}
+
+	return 0;
+}
diff --git a/source4/kdc/kpasswd-helper.h b/source4/kdc/kpasswd-helper.h
index 8fad81e0a5d..94a6e2acfdd 100644
--- a/source4/kdc/kpasswd-helper.h
+++ b/source4/kdc/kpasswd-helper.h
@@ -43,4 +43,6 @@ NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
 				    enum samPwdChangeReason *reject_reason,
 				    struct samr_DomInfo1 **dominfo);
 
+krb5_error_code kpasswd_check_non_tgt(struct auth_session_info *session_info,
+				      const char **error_string);
 #endif /* _KPASSWD_HELPER_H */
diff --git a/source4/kdc/kpasswd-service-heimdal.c b/source4/kdc/kpasswd-service-heimdal.c
index a0352d1ad35..4d009b9eb24 100644
--- a/source4/kdc/kpasswd-service-heimdal.c
+++ b/source4/kdc/kpasswd-service-heimdal.c
@@ -253,6 +253,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 {
 	struct auth_session_info *session_info;
 	NTSTATUS status;
+	krb5_error_code code;
 
 	status = gensec_session_info(gensec_security,
 				     mem_ctx,
@@ -264,6 +265,18 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 		return KRB5_KPASSWD_HARDERROR;
 	}
 
+	/*
+	 * Since the kpasswd service shares its keys with the krbtgt, we might
+	 * have received a TGT rather than a kpasswd ticket. We need to check
+	 * the ticket type to ensure that TGTs cannot be misused in this manner.
+	 */
+	code = kpasswd_check_non_tgt(session_info,
+				     error_string);
+	if (code != 0) {
+		DBG_WARNING("%s\n", *error_string);
+		return code;
+	}
+
 	switch(verno) {
 	case KRB5_KPASSWD_VERS_CHANGEPW: {
 		DATA_BLOB password = data_blob_null;
diff --git a/source4/kdc/kpasswd-service-mit.c b/source4/kdc/kpasswd-service-mit.c
index de4c6f3f622..6b051567b6e 100644
--- a/source4/kdc/kpasswd-service-mit.c
+++ b/source4/kdc/kpasswd-service-mit.c
@@ -332,6 +332,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 {
 	struct auth_session_info *session_info;
 	NTSTATUS status;
+	krb5_error_code code;
 
 	status = gensec_session_info(gensec_security,
 				     mem_ctx,
@@ -344,6 +345,18 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
 		return KRB5_KPASSWD_HARDERROR;
 	}
 
+	/*
+	 * Since the kpasswd service shares its keys with the krbtgt, we might
+	 * have received a TGT rather than a kpasswd ticket. We need to check
+	 * the ticket type to ensure that TGTs cannot be misused in this manner.
+	 */
+	code = kpasswd_check_non_tgt(session_info,
+				     error_string);
+	if (code != 0) {
+		DBG_WARNING("%s\n", *error_string);
+		return code;
+	}
+
 	switch(verno) {
 	case 1: {
 		DATA_BLOB password;
-- 
2.25.1


From 185a6d12935f55ad996de502e416114cc1f5aba0 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Thu, 23 Jun 2022 13:59:11 +1200
Subject: [PATCH 97/99] CVE-2022-2031 testprogs: Add test for short-lived
 ticket across an incoming trust

We ensure that the KDC does not reject a TGS-REQ with our short-lived
TGT over an incoming trust.

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

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
---
 testprogs/blackbox/test_kinit_trusts_heimdal.sh | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/testprogs/blackbox/test_kinit_trusts_heimdal.sh b/testprogs/blackbox/test_kinit_trusts_heimdal.sh
index 52b1ac6589c..29ea1c510ce 100755
--- a/testprogs/blackbox/test_kinit_trusts_heimdal.sh
+++ b/testprogs/blackbox/test_kinit_trusts_heimdal.sh
@@ -55,6 +55,10 @@ testit "kinit with password" $samba4kinit $enctype --password-file=$PREFIX/tmppa
 test_smbclient "Test login with user kerberos ccache" 'ls' "$unc" --use-krb5-ccache=$KRB5CCNAME || failed=`expr $failed + 1`
 rm -rf $KRB5CCNAME_PATH
 
+testit "kinit with password and two minute lifetime" $samba4kinit $enctype --password-file=$PREFIX/tmppassfile --request-pac --server=krbtgt/$REALM@$TRUST_REALM --lifetime=2m $TRUST_USERNAME@$TRUST_REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache and two minute lifetime" 'ls' "$unc" --use-krb5-ccache=$KRB5CCNAME || failed=`expr $failed + 1`
+rm -rf $KRB5CCNAME_PATH
+
 # Test with smbclient4
 smbclient="$samba4bindir/smbclient4"
 testit "kinit with password" $samba4kinit $enctype --password-file=$PREFIX/tmppassfile --request-pac $TRUST_USERNAME@$TRUST_REALM   || failed=`expr $failed + 1`
@@ -95,5 +99,5 @@ testit "wbinfo check outgoing trust pw" $VALGRIND $wbinfo --check-secret --domai
 
 test_smbclient "Test user login with the changed outgoing secret" 'ls' "$unc" --use-kerberos=required -U$USERNAME@$REALM%$PASSWORD || failed=`expr $failed + 1`
 
-rm -f $PREFIX/tmpccache tmpccfile tmppassfile tmpuserpassfile tmpuserccache
+rm -f $PREFIX/tmpccache $PREFIX/tmppassfile
 exit $failed
-- 
2.25.1
