FreeBSD Bugzilla – Attachment 236856 Details for
Bug 266641
net/samba413: Backport security fix from 4.14.14
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch file
net_samba413.patch (text/plain), 736.37 KB, created by
Yasuhiro Kimura
on 2022-09-27 03:26:34 UTC
(
hide
)
Description:
Patch file
Filename:
MIME Type:
Creator:
Yasuhiro Kimura
Created:
2022-09-27 03:26:34 UTC
Size:
736.37 KB
patch
obsolete
>From 0177f47c09f6b54cb35ce03d03b81f1fdce835bd Mon Sep 17 00:00:00 2001 >From: Yasuhiro Kimura <yasu@FreeBSD.org> >Date: Tue, 27 Sep 2022 08:47:17 +0900 >Subject: [PATCH] net/samba413: Backport security fix from 4.14.14 > >* Add upstream patch to fix configure error with Python 3.11. >* Fix plist error when AD_DC option is off and PYTHON3 option is on. >* Replace BIND911 option with BIND918 as dns/bind911 is removed from > ports tree and dns/bind918 is added instead. > >MFH: 2022Q3 >Security: CVE-2022-2031 >Security: CVE-2022-32742 >Security: CVE-2022-32744 >Security: CVE-2022-32745 >Security: CVE-2022-32746 >--- > net/samba413/Makefile | 8 +- > net/samba413/files/patch-samba-4.14.14 | 13366 +++++++++++++++++++++++ > net/samba413/files/patch-waf-2.0.20 | 1663 +++ > net/samba413/files/patch-waf-2.0.21 | 703 ++ > net/samba413/files/patch-waf-2.0.22 | 596 + > net/samba413/files/patch-waf-2.0.23 | 877 ++ > net/samba413/files/patch-waf-2.0.24 | 164 + > net/samba413/pkg-plist.ad_dc | 2 - > net/samba413/pkg-plist.python | 3 + > 9 files changed, 17376 insertions(+), 6 deletions(-) > create mode 100644 net/samba413/files/patch-samba-4.14.14 > create mode 100644 net/samba413/files/patch-waf-2.0.20 > create mode 100644 net/samba413/files/patch-waf-2.0.21 > create mode 100644 net/samba413/files/patch-waf-2.0.22 > create mode 100644 net/samba413/files/patch-waf-2.0.23 > create mode 100644 net/samba413/files/patch-waf-2.0.24 > >diff --git a/net/samba413/Makefile b/net/samba413/Makefile >index f1dea1c15f3d..ccbb438ecb6a 100644 >--- a/net/samba413/Makefile >+++ b/net/samba413/Makefile >@@ -1,6 +1,6 @@ > PORTNAME= ${SAMBA4_BASENAME}413 > PORTVERSION= ${SAMBA4_VERSION} >-PORTREVISION= 1 >+PORTREVISION= 2 > CATEGORIES?= net > MASTER_SITES= SAMBA/samba/stable SAMBA/samba/rc > DISTNAME= ${SAMBA4_DISTNAME} >@@ -96,7 +96,7 @@ OPTIONS_SINGLE_GSSAPI= GSSAPI_BUILTIN GSSAPI_MIT > OPTIONS_SINGLE_ZEROCONF= ZEROCONF_NONE AVAHI MDNSRESPONDER > > OPTIONS_RADIO= DNS >-OPTIONS_RADIO_DNS= NSUPDATE BIND911 BIND916 >+OPTIONS_RADIO_DNS= NSUPDATE BIND916 BIND918 > # Make those default options > OPTIONS_DEFAULT= AD_DC ADS DOCS FAM LDAP \ > PROFILE PYTHON3 QUOTAS SYSLOG UTMP \ >@@ -129,8 +129,8 @@ ZEROCONF_DESC= Zero configuration networking > ZEROCONF_NONE_DESC= Zeroconf support is absent > > DNS_DESC= DNS frontend >-BIND911_DESC= Use Bind 9.11 as AD DC DNS server frontend > BIND916_DESC= Use Bind 9.16 as AD DC DNS server frontend >+BIND918_DESC= Use Bind 9.18 as AD DC DNS server frontend > NSUPDATE_DESC= Use samba NSUPDATE utility for AD DC > ############################################################################## > # XXX: Unconditional dependencies which can't be switched off(if present in >@@ -299,8 +299,8 @@ MDNSRESPONDER_CONFIGURE_ENABLE= dnssd > MDNSRESPONDER_LIB_DEPENDS= libdns_sd.so:net/mDNSResponder > MDNSRESPONDER_VARS= SAMBA4_SERVICES+=mdnsd > ############################################################################## >-BIND911_RUN_DEPENDS= bind911>=9.11.0.0:dns/bind911 > BIND916_RUN_DEPENDS= bind916>=9.16.0.0:dns/bind916 >+BIND918_RUN_DEPENDS= bind918>=9.18.0.0:dns/bind918 > NSUPDATE_RUN_DEPENDS= samba-nsupdate:dns/samba-nsupdate > ############################################################################## > MEMORY_DEBUG_IMPLIES= DEBUG >diff --git a/net/samba413/files/patch-samba-4.14.14 b/net/samba413/files/patch-samba-4.14.14 >new file mode 100644 >index 000000000000..4127ab67308e >--- /dev/null >+++ b/net/samba413/files/patch-samba-4.14.14 >@@ -0,0 +1,13366 @@ >+From 5d958156c7e5d6c1da61d18fe4fd105b22639b56 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 14 Jun 2022 21:09:53 +1200 >+Subject: [PATCH 01/99] CVE-2022-32746 s4/dsdb/objectclass_attrs: Fix typo >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/objectclass_attrs.c | 2 +- >+ 1 file changed, 1 insertion(+), 1 deletion(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/objectclass_attrs.c source4/dsdb/samdb/ldb_modules/objectclass_attrs.c >+index 6ab46a729a2..2a77353cdfc 100644 >+--- source4/dsdb/samdb/ldb_modules/objectclass_attrs.c >++++ source4/dsdb/samdb/ldb_modules/objectclass_attrs.c >+@@ -263,7 +263,7 @@ static int attr_handler(struct oc_context *ac) >+ LDB_CONTROL_AS_SYSTEM_OID); >+ if (!dsdb_module_am_system(ac->module) && !as_system) { >+ ldb_asprintf_errstring(ldb, >+- "objectclass_attrs: attribute '%s' on entry '%s' must can only be modified as system", >++ "objectclass_attrs: attribute '%s' on entry '%s' can only be modified as system", >+ msg->elements[i].name, >+ ldb_dn_get_linearized(msg->dn)); >+ return LDB_ERR_CONSTRAINT_VIOLATION; >+-- >+2.25.1 >+ >+ >+From 51cbeff886fe01db463448f8655a43d10040dc8b Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 21 Jun 2022 15:37:15 +1200 >+Subject: [PATCH 02/99] CVE-2022-32746 s4:dsdb:tests: Add test for deleting a >+ disallowed SPN >+ >+If an account has an SPN that requires Write Property to set, we should >+still be able to delete it with just Validated Write. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ selftest/knownfail.d/acl-spn-delete | 1 + >+ source4/dsdb/tests/python/acl.py | 26 ++++++++++++++++++++++++++ >+ 2 files changed, 27 insertions(+) >+ create mode 100644 selftest/knownfail.d/acl-spn-delete >+ >+diff --git selftest/knownfail.d/acl-spn-delete selftest/knownfail.d/acl-spn-delete >+new file mode 100644 >+index 00000000000..32018413c49 >+--- /dev/null >++++ selftest/knownfail.d/acl-spn-delete >+@@ -0,0 +1 @@ >++^samba4.ldap.acl.python.*__main__.AclSPNTests.test_delete_disallowed_spn\( >+diff --git source4/dsdb/tests/python/acl.py source4/dsdb/tests/python/acl.py >+index df0fe12bf29..d90d3b3923f 100755 >+--- source4/dsdb/tests/python/acl.py >++++ source4/dsdb/tests/python/acl.py >+@@ -2286,6 +2286,32 @@ class AclSPNTests(AclTests): >+ else: >+ self.fail(f'able to add disallowed SPN {not_allowed_spn}') >+ >++ def test_delete_disallowed_spn(self): >++ # Grant Validated-SPN property. >++ mod = f'(OA;;SW;{security.GUID_DRS_VALIDATE_SPN};;{self.user_sid1})' >++ self.sd_utils.dacl_add_ace(self.computerdn, mod) >++ >++ spn_base = f'HOST/{self.computername}' >++ >++ not_allowed_spn = f'{spn_base}/{self.dcctx.get_domain_name()}' >++ >++ # Add a disallowed SPN as admin. >++ msg = Message(Dn(self.ldb_admin, self.computerdn)) >++ msg['servicePrincipalName'] = MessageElement(not_allowed_spn, >++ FLAG_MOD_ADD, >++ 'servicePrincipalName') >++ self.ldb_admin.modify(msg) >++ >++ # Ensure we are able to delete a disallowed SPN. >++ msg = Message(Dn(self.ldb_user1, self.computerdn)) >++ msg['servicePrincipalName'] = MessageElement(not_allowed_spn, >++ FLAG_MOD_DELETE, >++ 'servicePrincipalName') >++ try: >++ self.ldb_user1.modify(msg) >++ except LdbError: >++ self.fail(f'unable to delete disallowed SPN {not_allowed_spn}') >++ >+ >+ # tests SEC_ADS_LIST vs. SEC_ADS_LIST_OBJECT >+ @DynamicTestCase >+-- >+2.25.1 >+ >+ >+From a68553792a8512a2d266bbb86f064f78b5482a65 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 21 Jun 2022 14:41:02 +1200 >+Subject: [PATCH 03/99] CVE-2022-32746 s4/dsdb/partition: Fix LDB flags >+ comparison >+ >+LDB_FLAG_MOD_* values are not actually flags, and the previous >+comparison was equivalent to >+ >+(req_msg->elements[el_idx].flags & LDB_FLAG_MOD_MASK) != 0 >+ >+which is true whenever any of the LDB_FLAG_MOD_* values are set. Correct >+the expression to what it was probably intended to be. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/partition.c | 4 ++-- >+ 1 file changed, 2 insertions(+), 2 deletions(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/partition.c source4/dsdb/samdb/ldb_modules/partition.c >+index 2544a106d13..2d90ca5d1b3 100644 >+--- source4/dsdb/samdb/ldb_modules/partition.c >++++ source4/dsdb/samdb/ldb_modules/partition.c >+@@ -493,8 +493,8 @@ static int partition_copy_all_callback_action( >+ * them here too >+ */ >+ for (el_idx=0; el_idx < req_msg->num_elements; el_idx++) { >+- if (req_msg->elements[el_idx].flags & LDB_FLAG_MOD_DELETE >+- || ((req_msg->elements[el_idx].flags & LDB_FLAG_MOD_REPLACE) && >++ if (LDB_FLAG_MOD_TYPE(req_msg->elements[el_idx].flags) == LDB_FLAG_MOD_DELETE >++ || ((LDB_FLAG_MOD_TYPE(req_msg->elements[el_idx].flags) == LDB_FLAG_MOD_REPLACE) && >+ req_msg->elements[el_idx].num_values == 0)) { >+ if (ldb_msg_find_element(modify_msg, >+ req_msg->elements[el_idx].name) != NULL) { >+-- >+2.25.1 >+ >+ >+From 582ac171364f0c28f54eaf4f21b5bfa7569b5233 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 21 Jun 2022 14:49:51 +1200 >+Subject: [PATCH 04/99] CVE-2022-32746 s4:torture: Fix LDB flags comparison >+ >+LDB_FLAG_MOD_* values are not actually flags, and the previous >+comparison was equivalent to >+ >+(el->flags & LDB_FLAG_MOD_MASK) == 0 >+ >+which is only true if none of the LDB_FLAG_MOD_* values are set. Correct >+the expression to what it was probably intended to be. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/torture/drs/rpc/dssync.c | 4 +++- >+ 1 file changed, 3 insertions(+), 1 deletion(-) >+ >+diff --git source4/torture/drs/rpc/dssync.c source4/torture/drs/rpc/dssync.c >+index cde9f78692b..ff7ce2d9074 100644 >+--- source4/torture/drs/rpc/dssync.c >++++ source4/torture/drs/rpc/dssync.c >+@@ -527,7 +527,9 @@ static bool test_analyse_objects(struct torture_context *tctx, >+ el = &new_msg->elements[idx]; >+ a = dsdb_attribute_by_lDAPDisplayName(ldap_schema, >+ el->name); >+- if (!(el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE))) { >++ if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD && >++ LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE) >++ { >+ /* DRS only value */ >+ is_warning = false; >+ } else if (a->linkID & 1) { >+-- >+2.25.1 >+ >+ >+From 0526d27e9eddd9c2a54434cf0dcdb136a6c659e4 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 21 Jun 2022 15:22:47 +1200 >+Subject: [PATCH 05/99] CVE-2022-32746 s4/dsdb/acl: Fix LDB flags comparison >+ >+LDB_FLAG_MOD_* values are not actually flags, and the previous >+comparison was equivalent to >+ >+(el->flags & LDB_FLAG_MOD_MASK) == 0 >+ >+which is only true if none of the LDB_FLAG_MOD_* values are set, so we >+would not successfully return if the element was a DELETE. Correct the >+expression to what it was intended to be. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ selftest/knownfail.d/acl-spn-delete | 1 - >+ source4/dsdb/samdb/ldb_modules/acl.c | 5 +++-- >+ 2 files changed, 3 insertions(+), 3 deletions(-) >+ delete mode 100644 selftest/knownfail.d/acl-spn-delete >+ >+diff --git selftest/knownfail.d/acl-spn-delete selftest/knownfail.d/acl-spn-delete >+deleted file mode 100644 >+index 32018413c49..00000000000 >+--- selftest/knownfail.d/acl-spn-delete >++++ /dev/null >+@@ -1 +0,0 @@ >+-^samba4.ldap.acl.python.*__main__.AclSPNTests.test_delete_disallowed_spn\( >+diff --git source4/dsdb/samdb/ldb_modules/acl.c source4/dsdb/samdb/ldb_modules/acl.c >+index 21e83276bfd..8016a2d4bd0 100644 >+--- source4/dsdb/samdb/ldb_modules/acl.c >++++ source4/dsdb/samdb/ldb_modules/acl.c >+@@ -734,8 +734,9 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, >+ * If not add or replace (eg delete), >+ * return success >+ */ >+- if ((el->flags >+- & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0) { >++ if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD && >++ LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE) >++ { >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+-- >+2.25.1 >+ >+ >+From 2869b5aa3148869edf0d079266542aef6e64608e Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Wed, 16 Feb 2022 12:43:52 +1300 >+Subject: [PATCH 06/99] CVE-2022-32746 ldb:rdn_name: Use LDB_FLAG_MOD_TYPE() >+ for flags equality check >+ >+Now unrelated flags will no longer affect the result. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ lib/ldb/modules/rdn_name.c | 2 +- >+ 1 file changed, 1 insertion(+), 1 deletion(-) >+ >+diff --git lib/ldb/modules/rdn_name.c lib/ldb/modules/rdn_name.c >+index e69ad9315ae..25cffe07591 100644 >+--- lib/ldb/modules/rdn_name.c >++++ lib/ldb/modules/rdn_name.c >+@@ -545,7 +545,7 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req) >+ if (e != NULL) { >+ ldb_asprintf_errstring(ldb, "Modify of 'distinguishedName' on %s not permitted, must use 'rename' operation instead", >+ ldb_dn_get_linearized(req->op.mod.message->dn)); >+- if (e->flags == LDB_FLAG_MOD_REPLACE) { >++ if (LDB_FLAG_MOD_TYPE(e->flags) == LDB_FLAG_MOD_REPLACE) { >+ return LDB_ERR_CONSTRAINT_VIOLATION; >+ } else { >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+-- >+2.25.1 >+ >+ >+From 535b5a366a2ad054f729e57e282e402cf13b2efc Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 14 Jun 2022 19:49:19 +1200 >+Subject: [PATCH 07/99] CVE-2022-32746 s4/dsdb/repl_meta_data: Use >+ LDB_FLAG_MOD_TYPE() for flags equality check >+ >+Now unrelated flags will no longer affect the result. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 8 ++++---- >+ 1 file changed, 4 insertions(+), 4 deletions(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/repl_meta_data.c source4/dsdb/samdb/ldb_modules/repl_meta_data.c >+index ab506cec488..29ffda75c87 100644 >+--- source4/dsdb/samdb/ldb_modules/repl_meta_data.c >++++ source4/dsdb/samdb/ldb_modules/repl_meta_data.c >+@@ -3525,7 +3525,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) >+ return ldb_module_operr(module); >+ } >+ >+- if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_REPLACE) { >++ if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[0].flags) != LDB_FLAG_MOD_REPLACE) { >+ return ldb_module_operr(module); >+ } >+ >+@@ -3558,11 +3558,11 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) >+ return ldb_module_operr(module); >+ } >+ >+- if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_DELETE) { >++ if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[0].flags) != LDB_FLAG_MOD_DELETE) { >+ return ldb_module_operr(module); >+ } >+ >+- if (req->op.mod.message->elements[1].flags != LDB_FLAG_MOD_ADD) { >++ if (LDB_FLAG_MOD_TYPE(req->op.mod.message->elements[1].flags) != LDB_FLAG_MOD_ADD) { >+ return ldb_module_operr(module); >+ } >+ >+@@ -3645,7 +3645,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) >+ return ldb_module_operr(module); >+ } >+ >+- if (msg->elements[0].flags != LDB_FLAG_MOD_ADD) { >++ if (LDB_FLAG_MOD_TYPE(msg->elements[0].flags) != LDB_FLAG_MOD_ADD) { >+ talloc_free(ac); >+ return ldb_module_operr(module); >+ } >+-- >+2.25.1 >+ >+ >+From bedd0b768c3f92645af033399aefd7ee971d9150 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 14 Jun 2022 21:11:33 +1200 >+Subject: [PATCH 08/99] CVE-2022-32746 s4/dsdb/tombstone_reanimate: Use >+ LDB_FLAG_MOD_TYPE() for flags equality check >+ >+Now unrelated flags will no longer affect the result. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c | 4 ++-- >+ 1 file changed, 2 insertions(+), 2 deletions(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c >+index 64e05195798..5f8911c66be 100644 >+--- source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c >++++ source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c >+@@ -104,7 +104,7 @@ static bool is_tombstone_reanimate_request(struct ldb_request *req, >+ if (el_dn == NULL) { >+ return false; >+ } >+- if (el_dn->flags != LDB_FLAG_MOD_REPLACE) { >++ if (LDB_FLAG_MOD_TYPE(el_dn->flags) != LDB_FLAG_MOD_REPLACE) { >+ return false; >+ } >+ if (el_dn->num_values != 1) { >+@@ -117,7 +117,7 @@ static bool is_tombstone_reanimate_request(struct ldb_request *req, >+ return false; >+ } >+ >+- if (el_deleted->flags != LDB_FLAG_MOD_DELETE) { >++ if (LDB_FLAG_MOD_TYPE(el_deleted->flags) != LDB_FLAG_MOD_DELETE) { >+ return false; >+ } >+ >+-- >+2.25.1 >+ >+ >+From 49dd9042f4ee380fa1dafcebcb54d0e1f0852463 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Tue, 14 Jun 2022 21:12:39 +1200 >+Subject: [PATCH 09/99] CVE-2022-32746 s4/registry: Use LDB_FLAG_MOD_TYPE() for >+ flags equality check >+ >+Now unrelated flags will no longer affect the result. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/lib/registry/ldb.c | 2 +- >+ 1 file changed, 1 insertion(+), 1 deletion(-) >+ >+diff --git source4/lib/registry/ldb.c source4/lib/registry/ldb.c >+index e089355975b..db383a560da 100644 >+--- source4/lib/registry/ldb.c >++++ source4/lib/registry/ldb.c >+@@ -859,7 +859,7 @@ static WERROR ldb_set_value(struct hive_key *parent, >+ >+ /* Try first a "modify" and if this doesn't work do try an "add" */ >+ for (i = 0; i < msg->num_elements; i++) { >+- if (msg->elements[i].flags != LDB_FLAG_MOD_DELETE) { >++ if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) != LDB_FLAG_MOD_DELETE) { >+ msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; >+ } >+ } >+-- >+2.25.1 >+ >+ >+From faa61ab3053d077ac9d0aa67e955217e85b660f4 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Mon, 21 Feb 2022 16:10:32 +1300 >+Subject: [PATCH 10/99] CVE-2022-32746 ldb: Add flag to mark message element >+ values as shared >+ >+When making a shallow copy of an ldb message, mark the message elements >+of the copy as sharing their values with the message elements in the >+original message. >+ >+This flag value will be heeded in the next commit. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ lib/ldb/common/ldb_msg.c | 43 +++++++++++++++++++++++++++++++----- >+ lib/ldb/include/ldb_module.h | 6 +++++ >+ 2 files changed, 43 insertions(+), 6 deletions(-) >+ >+diff --git lib/ldb/common/ldb_msg.c lib/ldb/common/ldb_msg.c >+index 57dfc5a04c2..2a9ce384bb9 100644 >+--- lib/ldb/common/ldb_msg.c >++++ lib/ldb/common/ldb_msg.c >+@@ -833,11 +833,7 @@ void ldb_msg_sort_elements(struct ldb_message *msg) >+ ldb_msg_element_compare_name); >+ } >+ >+-/* >+- shallow copy a message - copying only the elements array so that the caller >+- can safely add new elements without changing the message >+-*/ >+-struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, >++static struct ldb_message *ldb_msg_copy_shallow_impl(TALLOC_CTX *mem_ctx, >+ const struct ldb_message *msg) >+ { >+ struct ldb_message *msg2; >+@@ -863,6 +859,35 @@ failed: >+ return NULL; >+ } >+ >++/* >++ shallow copy a message - copying only the elements array so that the caller >++ can safely add new elements without changing the message >++*/ >++struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, >++ const struct ldb_message *msg) >++{ >++ struct ldb_message *msg2; >++ unsigned int i; >++ >++ msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg); >++ if (msg2 == NULL) { >++ return NULL; >++ } >++ >++ for (i = 0; i < msg2->num_elements; ++i) { >++ /* >++ * Mark this message's elements as sharing their values with the >++ * original message, so that we don't inadvertently modify or >++ * free them. We don't mark the original message element as >++ * shared, so the original message element should not be >++ * modified or freed while the shallow copy lives. >++ */ >++ struct ldb_message_element *el = &msg2->elements[i]; >++ el->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES; >++ } >++ >++ return msg2; >++} >+ >+ /* >+ copy a message, allocating new memory for all parts >+@@ -873,7 +898,7 @@ struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, >+ struct ldb_message *msg2; >+ unsigned int i, j; >+ >+- msg2 = ldb_msg_copy_shallow(mem_ctx, msg); >++ msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg); >+ if (msg2 == NULL) return NULL; >+ >+ if (msg2->dn != NULL) { >+@@ -894,6 +919,12 @@ struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, >+ goto failed; >+ } >+ } >++ >++ /* >++ * Since we copied this element's values, we can mark them as >++ * not shared. >++ */ >++ el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES; >+ } >+ >+ return msg2; >+diff --git lib/ldb/include/ldb_module.h lib/ldb/include/ldb_module.h >+index 8c1e5ee7936..4c7c85a17f0 100644 >+--- lib/ldb/include/ldb_module.h >++++ lib/ldb/include/ldb_module.h >+@@ -96,6 +96,12 @@ struct ldb_module; >+ */ >+ #define LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX 0x100 >+ >++/* >++ * indicates that this element's values are shared with another element (for >++ * example, in a shallow copy of an ldb_message) and should not be freed >++ */ >++#define LDB_FLAG_INTERNAL_SHARED_VALUES 0x200 >++ >+ /* an extended match rule that always fails to match */ >+ #define SAMBA_LDAP_MATCH_ALWAYS_FALSE "1.3.6.1.4.1.7165.4.5.1" >+ >+-- >+2.25.1 >+ >+ >+From 4e5fb78c3dcff60aa8fd4b07dad4660bbb30532b Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Wed, 16 Feb 2022 12:35:13 +1300 >+Subject: [PATCH 11/99] CVE-2022-32746 ldb: Ensure shallow copy modifications >+ do not affect original message >+ >+Using the newly added ldb flag, we can now detect when a message has >+been shallow-copied so that its elements share their values with the >+original message elements. Then when adding values to the copied >+message, we now make a copy of the shared values array first. >+ >+This should prevent a use-after-free that occurred in LDB modules when >+new values were added to a shallow copy of a message by calling >+talloc_realloc() on the original values array, invalidating the 'values' >+pointer in the original message element. The original values pointer can >+later be used in the database audit logging module which logs database >+requests, and potentially cause a crash. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ lib/ldb/common/ldb_msg.c | 52 ++++++++++++++++++++++++++++++++------ >+ lib/ldb/include/ldb.h | 6 +++++ >+ source4/dsdb/common/util.c | 20 +++++---------- >+ 3 files changed, 56 insertions(+), 22 deletions(-) >+ >+diff --git lib/ldb/common/ldb_msg.c lib/ldb/common/ldb_msg.c >+index 2a9ce384bb9..44d3b29e9a7 100644 >+--- lib/ldb/common/ldb_msg.c >++++ lib/ldb/common/ldb_msg.c >+@@ -417,6 +417,47 @@ int ldb_msg_add(struct ldb_message *msg, >+ return LDB_SUCCESS; >+ } >+ >++/* >++ * add a value to a message element >++ */ >++int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx, >++ struct ldb_message_element *el, >++ const struct ldb_val *val) >++{ >++ struct ldb_val *vals; >++ >++ if (el->flags & LDB_FLAG_INTERNAL_SHARED_VALUES) { >++ /* >++ * Another message is using this message element's values array, >++ * so we don't want to make any modifications to the original >++ * message, or potentially invalidate its own values by calling >++ * talloc_realloc(). Make a copy instead. >++ */ >++ el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES; >++ >++ vals = talloc_array(mem_ctx, struct ldb_val, >++ el->num_values + 1); >++ if (vals == NULL) { >++ return LDB_ERR_OPERATIONS_ERROR; >++ } >++ >++ if (el->values != NULL) { >++ memcpy(vals, el->values, el->num_values * sizeof(struct ldb_val)); >++ } >++ } else { >++ vals = talloc_realloc(mem_ctx, el->values, struct ldb_val, >++ el->num_values + 1); >++ if (vals == NULL) { >++ return LDB_ERR_OPERATIONS_ERROR; >++ } >++ } >++ el->values = vals; >++ el->values[el->num_values] = *val; >++ el->num_values++; >++ >++ return LDB_SUCCESS; >++} >++ >+ /* >+ add a value to a message >+ */ >+@@ -426,7 +467,6 @@ int ldb_msg_add_value(struct ldb_message *msg, >+ struct ldb_message_element **return_el) >+ { >+ struct ldb_message_element *el; >+- struct ldb_val *vals; >+ int ret; >+ >+ el = ldb_msg_find_element(msg, attr_name); >+@@ -437,14 +477,10 @@ int ldb_msg_add_value(struct ldb_message *msg, >+ } >+ } >+ >+- vals = talloc_realloc(msg->elements, el->values, struct ldb_val, >+- el->num_values+1); >+- if (!vals) { >+- return LDB_ERR_OPERATIONS_ERROR; >++ ret = ldb_msg_element_add_value(msg->elements, el, val); >++ if (ret != LDB_SUCCESS) { >++ return ret; >+ } >+- el->values = vals; >+- el->values[el->num_values] = *val; >+- el->num_values++; >+ >+ if (return_el) { >+ *return_el = el; >+diff --git lib/ldb/include/ldb.h lib/ldb/include/ldb.h >+index bc44157eaf4..129beefeaf5 100644 >+--- lib/ldb/include/ldb.h >++++ lib/ldb/include/ldb.h >+@@ -1981,6 +1981,12 @@ int ldb_msg_add_empty(struct ldb_message *msg, >+ int flags, >+ struct ldb_message_element **return_el); >+ >++/** >++ add a value to a message element >++*/ >++int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx, >++ struct ldb_message_element *el, >++ const struct ldb_val *val); >+ /** >+ add a element to a ldb_message >+ */ >+diff --git source4/dsdb/common/util.c source4/dsdb/common/util.c >+index 5ce4c0a5e33..577b2a33873 100644 >+--- source4/dsdb/common/util.c >++++ source4/dsdb/common/util.c >+@@ -816,7 +816,7 @@ int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, >+ const char *value) >+ { >+ struct ldb_message_element *el; >+- struct ldb_val val, *vals; >++ struct ldb_val val; >+ char *v; >+ unsigned int i; >+ bool found = false; >+@@ -851,14 +851,10 @@ int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, >+ } >+ } >+ >+- vals = talloc_realloc(msg->elements, el->values, struct ldb_val, >+- el->num_values + 1); >+- if (vals == NULL) { >++ ret = ldb_msg_element_add_value(msg->elements, el, &val); >++ if (ret != LDB_SUCCESS) { >+ return ldb_oom(sam_ldb); >+ } >+- el->values = vals; >+- el->values[el->num_values] = val; >+- ++(el->num_values); >+ >+ return LDB_SUCCESS; >+ } >+@@ -872,7 +868,7 @@ int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, >+ const char *value) >+ { >+ struct ldb_message_element *el; >+- struct ldb_val val, *vals; >++ struct ldb_val val; >+ char *v; >+ unsigned int i; >+ bool found = false; >+@@ -907,14 +903,10 @@ int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, >+ } >+ } >+ >+- vals = talloc_realloc(msg->elements, el->values, struct ldb_val, >+- el->num_values + 1); >+- if (vals == NULL) { >++ ret = ldb_msg_element_add_value(msg->elements, el, &val); >++ if (ret != LDB_SUCCESS) { >+ return ldb_oom(sam_ldb); >+ } >+- el->values = vals; >+- el->values[el->num_values] = val; >+- ++(el->num_values); >+ >+ return LDB_SUCCESS; >+ } >+-- >+2.25.1 >+ >+ >+From 512a2617b1593bdc16caeeeda4312a581cbb34e9 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Wed, 16 Feb 2022 16:30:03 +1300 >+Subject: [PATCH 12/99] CVE-2022-32746 ldb: Add functions for appending to an >+ ldb_message >+ >+Currently, there are many places where we use ldb_msg_add_empty() to add >+an empty element to a message, and then call ldb_msg_add_value() or >+similar to add values to that element. However, this performs an >+unnecessary search of the message's elements to locate the new element. >+Moreover, if an element with the same attribute name already exists >+earlier in the message, the values will be added to that element, >+instead of to the intended newly added element. >+ >+A similar pattern exists where we add values to a message, and then call >+ldb_msg_find_element() to locate that message element and sets its flags >+to (e.g.) LDB_FLAG_MOD_REPLACE. This also performs an unnecessary >+search, and may locate the wrong message element for setting the flags. >+ >+To avoid these problems, add functions for appending a value to a >+message, so that a particular value can be added to the end of a message >+in a single operation. >+ >+For ADD requests, it is important that no two message elements share the >+same attribute name, otherwise things will break. (Normally, >+ldb_msg_normalize() is called before processing the request to help >+ensure this.) Thus, we must be careful not to append an attribute to an >+ADD message, unless we are sure (e.g. through ldb_msg_find_element()) >+that an existing element for that attribute is not present. >+ >+These functions will be used in the next commit. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ lib/ldb/common/ldb_msg.c | 165 ++++++++++++++++++++++++++++++++++++++- >+ lib/ldb/include/ldb.h | 24 ++++++ >+ 2 files changed, 185 insertions(+), 4 deletions(-) >+ >+diff --git lib/ldb/common/ldb_msg.c lib/ldb/common/ldb_msg.c >+index 44d3b29e9a7..9cd7998e21c 100644 >+--- lib/ldb/common/ldb_msg.c >++++ lib/ldb/common/ldb_msg.c >+@@ -509,12 +509,15 @@ int ldb_msg_add_steal_value(struct ldb_message *msg, >+ >+ >+ /* >+- add a string element to a message >++ add a string element to a message, specifying flags >+ */ >+-int ldb_msg_add_string(struct ldb_message *msg, >+- const char *attr_name, const char *str) >++int ldb_msg_add_string_flags(struct ldb_message *msg, >++ const char *attr_name, const char *str, >++ int flags) >+ { >+ struct ldb_val val; >++ int ret; >++ struct ldb_message_element *el = NULL; >+ >+ val.data = discard_const_p(uint8_t, str); >+ val.length = strlen(str); >+@@ -524,7 +527,25 @@ int ldb_msg_add_string(struct ldb_message *msg, >+ return LDB_SUCCESS; >+ } >+ >+- return ldb_msg_add_value(msg, attr_name, &val, NULL); >++ ret = ldb_msg_add_value(msg, attr_name, &val, &el); >++ if (ret != LDB_SUCCESS) { >++ return ret; >++ } >++ >++ if (flags != 0) { >++ el->flags = flags; >++ } >++ >++ return LDB_SUCCESS; >++} >++ >++/* >++ add a string element to a message >++*/ >++int ldb_msg_add_string(struct ldb_message *msg, >++ const char *attr_name, const char *str) >++{ >++ return ldb_msg_add_string_flags(msg, attr_name, str, 0); >+ } >+ >+ /* >+@@ -586,6 +607,142 @@ int ldb_msg_add_fmt(struct ldb_message *msg, >+ return ldb_msg_add_steal_value(msg, attr_name, &val); >+ } >+ >++static int ldb_msg_append_value_impl(struct ldb_message *msg, >++ const char *attr_name, >++ const struct ldb_val *val, >++ int flags, >++ struct ldb_message_element **return_el) >++{ >++ struct ldb_message_element *el = NULL; >++ int ret; >++ >++ ret = ldb_msg_add_empty(msg, attr_name, flags, &el); >++ if (ret != LDB_SUCCESS) { >++ return ret; >++ } >++ >++ ret = ldb_msg_element_add_value(msg->elements, el, val); >++ if (ret != LDB_SUCCESS) { >++ return ret; >++ } >++ >++ if (return_el != NULL) { >++ *return_el = el; >++ } >++ >++ return LDB_SUCCESS; >++} >++ >++/* >++ append a value to a message >++*/ >++int ldb_msg_append_value(struct ldb_message *msg, >++ const char *attr_name, >++ const struct ldb_val *val, >++ int flags) >++{ >++ return ldb_msg_append_value_impl(msg, attr_name, val, flags, NULL); >++} >++ >++/* >++ append a value to a message, stealing it into the 'right' place >++*/ >++int ldb_msg_append_steal_value(struct ldb_message *msg, >++ const char *attr_name, >++ struct ldb_val *val, >++ int flags) >++{ >++ int ret; >++ struct ldb_message_element *el = NULL; >++ >++ ret = ldb_msg_append_value_impl(msg, attr_name, val, flags, &el); >++ if (ret == LDB_SUCCESS) { >++ talloc_steal(el->values, val->data); >++ } >++ return ret; >++} >++ >++/* >++ append a string element to a message, stealing it into the 'right' place >++*/ >++int ldb_msg_append_steal_string(struct ldb_message *msg, >++ const char *attr_name, char *str, >++ int flags) >++{ >++ struct ldb_val val; >++ >++ val.data = (uint8_t *)str; >++ val.length = strlen(str); >++ >++ if (val.length == 0) { >++ /* allow empty strings as non-existent attributes */ >++ return LDB_SUCCESS; >++ } >++ >++ return ldb_msg_append_steal_value(msg, attr_name, &val, flags); >++} >++ >++/* >++ append a string element to a message >++*/ >++int ldb_msg_append_string(struct ldb_message *msg, >++ const char *attr_name, const char *str, int flags) >++{ >++ struct ldb_val val; >++ >++ val.data = discard_const_p(uint8_t, str); >++ val.length = strlen(str); >++ >++ if (val.length == 0) { >++ /* allow empty strings as non-existent attributes */ >++ return LDB_SUCCESS; >++ } >++ >++ return ldb_msg_append_value(msg, attr_name, &val, flags); >++} >++ >++/* >++ append a DN element to a message >++ WARNING: this uses the linearized string from the dn, and does not >++ copy the string. >++*/ >++int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name, >++ struct ldb_dn *dn, int flags) >++{ >++ char *str = ldb_dn_alloc_linearized(msg, dn); >++ >++ if (str == NULL) { >++ /* we don't want to have unknown DNs added */ >++ return LDB_ERR_OPERATIONS_ERROR; >++ } >++ >++ return ldb_msg_append_steal_string(msg, attr_name, str, flags); >++} >++ >++/* >++ append a printf formatted element to a message >++*/ >++int ldb_msg_append_fmt(struct ldb_message *msg, int flags, >++ const char *attr_name, const char *fmt, ...) >++{ >++ struct ldb_val val; >++ va_list ap; >++ char *str = NULL; >++ >++ va_start(ap, fmt); >++ str = talloc_vasprintf(msg, fmt, ap); >++ va_end(ap); >++ >++ if (str == NULL) { >++ return LDB_ERR_OPERATIONS_ERROR; >++ } >++ >++ val.data = (uint8_t *)str; >++ val.length = strlen(str); >++ >++ return ldb_msg_append_steal_value(msg, attr_name, &val, flags); >++} >++ >+ /* >+ compare two ldb_message_element structures >+ assumes case sensitive comparison >+diff --git lib/ldb/include/ldb.h lib/ldb/include/ldb.h >+index 129beefeaf5..63d8aedd672 100644 >+--- lib/ldb/include/ldb.h >++++ lib/ldb/include/ldb.h >+@@ -2002,12 +2002,36 @@ int ldb_msg_add_steal_value(struct ldb_message *msg, >+ struct ldb_val *val); >+ int ldb_msg_add_steal_string(struct ldb_message *msg, >+ const char *attr_name, char *str); >++int ldb_msg_add_string_flags(struct ldb_message *msg, >++ const char *attr_name, const char *str, >++ int flags); >+ int ldb_msg_add_string(struct ldb_message *msg, >+ const char *attr_name, const char *str); >+ int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name, >+ struct ldb_dn *dn); >+ int ldb_msg_add_fmt(struct ldb_message *msg, >+ const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); >++/** >++ append a element to a ldb_message >++*/ >++int ldb_msg_append_value(struct ldb_message *msg, >++ const char *attr_name, >++ const struct ldb_val *val, >++ int flags); >++int ldb_msg_append_steal_value(struct ldb_message *msg, >++ const char *attr_name, >++ struct ldb_val *val, >++ int flags); >++int ldb_msg_append_steal_string(struct ldb_message *msg, >++ const char *attr_name, char *str, >++ int flags); >++int ldb_msg_append_string(struct ldb_message *msg, >++ const char *attr_name, const char *str, >++ int flags); >++int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name, >++ struct ldb_dn *dn, int flags); >++int ldb_msg_append_fmt(struct ldb_message *msg, int flags, >++ const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(4,5); >+ >+ /** >+ compare two message elements - return 0 on match >+-- >+2.25.1 >+ >+ >+From f419753d1c7a373fb32ffe20930a6e084e44b44d Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Mon, 21 Feb 2022 16:27:37 +1300 >+Subject: [PATCH 13/99] CVE-2022-32746 ldb: Make use of functions for appending >+ to an ldb_message >+ >+This aims to minimise usage of the error-prone pattern of searching for >+a just-added message element in order to make modifications to it (and >+potentially finding the wrong element). >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ lib/ldb/ldb_map/ldb_map.c | 5 +- >+ lib/ldb/ldb_map/ldb_map_inbound.c | 9 +- >+ lib/ldb/modules/rdn_name.c | 22 +--- >+ source3/passdb/pdb_samba_dsdb.c | 14 +-- >+ source4/dns_server/dnsserver_common.c | 12 +- >+ source4/dsdb/common/util.c | 114 ++++++++++++++---- >+ source4/dsdb/samdb/ldb_modules/descriptor.c | 10 +- >+ source4/dsdb/samdb/ldb_modules/objectguid.c | 20 +-- >+ .../dsdb/samdb/ldb_modules/partition_init.c | 14 +-- >+ .../dsdb/samdb/ldb_modules/repl_meta_data.c | 24 +--- >+ source4/dsdb/samdb/ldb_modules/samldb.c | 78 +++++------- >+ .../samdb/ldb_modules/tombstone_reanimate.c | 12 +- >+ source4/nbt_server/wins/winsdb.c | 13 +- >+ source4/rpc_server/lsa/dcesrv_lsa.c | 55 +++------ >+ source4/winbind/idmap.c | 10 +- >+ 15 files changed, 183 insertions(+), 229 deletions(-) >+ >+diff --git lib/ldb/ldb_map/ldb_map.c lib/ldb/ldb_map/ldb_map.c >+index b453dff80d2..c7b0c228631 100644 >+--- lib/ldb/ldb_map/ldb_map.c >++++ lib/ldb/ldb_map/ldb_map.c >+@@ -946,10 +946,7 @@ struct ldb_request *map_build_fixup_req(struct map_context *ac, >+ if ( ! dn || ! ldb_dn_validate(msg->dn)) { >+ goto failed; >+ } >+- if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) { >+- goto failed; >+- } >+- if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) { >++ if (ldb_msg_append_string(msg, IS_MAPPED, dn, LDB_FLAG_MOD_REPLACE) != 0) { >+ goto failed; >+ } >+ >+diff --git lib/ldb/ldb_map/ldb_map_inbound.c lib/ldb/ldb_map/ldb_map_inbound.c >+index 324295737da..50b9427c26c 100644 >+--- lib/ldb/ldb_map/ldb_map_inbound.c >++++ lib/ldb/ldb_map/ldb_map_inbound.c >+@@ -569,12 +569,9 @@ static int map_modify_do_local(struct map_context *ac) >+ /* No local record present, add it instead */ >+ /* Add local 'IS_MAPPED' */ >+ /* TODO: use GUIDs here instead */ >+- if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED, >+- LDB_FLAG_MOD_ADD, NULL) != 0) { >+- return LDB_ERR_OPERATIONS_ERROR; >+- } >+- ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED, >+- ac->remote_req->op.mod.message->dn); >++ ret = ldb_msg_append_linearized_dn(ac->local_msg, IS_MAPPED, >++ ac->remote_req->op.mod.message->dn, >++ LDB_FLAG_MOD_ADD); >+ if (ret != 0) { >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+diff --git lib/ldb/modules/rdn_name.c lib/ldb/modules/rdn_name.c >+index 25cffe07591..3cb62bf567b 100644 >+--- lib/ldb/modules/rdn_name.c >++++ lib/ldb/modules/rdn_name.c >+@@ -308,16 +308,10 @@ static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares) >+ } >+ rdn_val = ldb_val_dup(msg, rdn_val_p); >+ >+- if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { >++ if (ldb_msg_append_value(msg, rdn_name, &rdn_val, LDB_FLAG_MOD_REPLACE) != 0) { >+ goto error; >+ } >+- if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { >+- goto error; >+- } >+- if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { >+- goto error; >+- } >+- if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { >++ if (ldb_msg_append_value(msg, "name", &rdn_val, LDB_FLAG_MOD_REPLACE) != 0) { >+ goto error; >+ } >+ >+@@ -466,11 +460,7 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req) >+ if (ret != 0) { >+ return ldb_module_oom(module); >+ } >+- ret = ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_ADD, NULL); >+- if (ret != 0) { >+- return ldb_module_oom(module); >+- } >+- ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL); >++ ret = ldb_msg_append_value(msg, rdn_name, &rdn_val, LDB_FLAG_MOD_ADD); >+ if (ret != 0) { >+ return ldb_module_oom(module); >+ } >+@@ -479,11 +469,7 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req) >+ if (ret != 0) { >+ return ldb_module_oom(module); >+ } >+- ret = ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_ADD, NULL); >+- if (ret != 0) { >+- return ldb_module_oom(module); >+- } >+- ret = ldb_msg_add_value(msg, "name", &rdn_val, NULL); >++ ret = ldb_msg_append_value(msg, "name", &rdn_val, LDB_FLAG_MOD_ADD); >+ if (ret != 0) { >+ return ldb_module_oom(module); >+ } >+diff --git source3/passdb/pdb_samba_dsdb.c source3/passdb/pdb_samba_dsdb.c >+index 93e8f5bebe6..b2063825c04 100644 >+--- source3/passdb/pdb_samba_dsdb.c >++++ source3/passdb/pdb_samba_dsdb.c >+@@ -2855,18 +2855,10 @@ static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m, >+ } >+ >+ msg->num_elements = 0; >+- ret = ldb_msg_add_empty(msg, "trustAuthOutgoing", >+- LDB_FLAG_MOD_REPLACE, NULL); >++ ret = ldb_msg_append_value(msg, "trustAuthOutgoing", >++ &new_val, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+- DEBUG(0, ("ldb_msg_add_empty() failed\n")); >+- TALLOC_FREE(tmp_ctx); >+- ldb_transaction_cancel(state->ldb); >+- return false; >+- } >+- ret = ldb_msg_add_value(msg, "trustAuthOutgoing", >+- &new_val, NULL); >+- if (ret != LDB_SUCCESS) { >+- DEBUG(0, ("ldb_msg_add_value() failed\n")); >++ DEBUG(0, ("ldb_msg_append_value() failed\n")); >+ TALLOC_FREE(tmp_ctx); >+ ldb_transaction_cancel(state->ldb); >+ return false; >+diff --git source4/dns_server/dnsserver_common.c source4/dns_server/dnsserver_common.c >+index bcb0d087faf..cb9a082ebf6 100644 >+--- source4/dns_server/dnsserver_common.c >++++ source4/dns_server/dnsserver_common.c >+@@ -1092,15 +1092,9 @@ WERROR dns_common_replace(struct ldb_context *samdb, >+ } >+ >+ if (was_tombstoned || become_tombstoned) { >+- ret = ldb_msg_add_empty(msg, "dNSTombstoned", >+- LDB_FLAG_MOD_REPLACE, NULL); >+- if (ret != LDB_SUCCESS) { >+- werr = DNS_ERR(SERVER_FAILURE); >+- goto exit; >+- } >+- >+- ret = ldb_msg_add_fmt(msg, "dNSTombstoned", "%s", >+- become_tombstoned ? "TRUE" : "FALSE"); >++ ret = ldb_msg_append_fmt(msg, LDB_FLAG_MOD_REPLACE, >++ "dNSTombstoned", "%s", >++ become_tombstoned ? "TRUE" : "FALSE"); >+ if (ret != LDB_SUCCESS) { >+ werr = DNS_ERR(SERVER_FAILURE); >+ goto exit; >+diff --git source4/dsdb/common/util.c source4/dsdb/common/util.c >+index 577b2a33873..10d6ea8883b 100644 >+--- source4/dsdb/common/util.c >++++ source4/dsdb/common/util.c >+@@ -924,6 +924,16 @@ int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct l >+ return ldb_msg_add_string(msg, attr_name, s); >+ } >+ >++int samdb_msg_add_int_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, >++ const char *attr_name, int v, int flags) >++{ >++ const char *s = talloc_asprintf(mem_ctx, "%d", v); >++ if (s == NULL) { >++ return ldb_oom(sam_ldb); >++ } >++ return ldb_msg_add_string_flags(msg, attr_name, s, flags); >++} >++ >+ /* >+ * Add an unsigned int element to a message >+ * >+@@ -942,6 +952,12 @@ int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct >+ return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v); >+ } >+ >++int samdb_msg_add_uint_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, >++ const char *attr_name, unsigned int v, int flags) >++{ >++ return samdb_msg_add_int_flags(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags); >++} >++ >+ /* >+ add a (signed) int64_t element to a message >+ */ >+@@ -973,6 +989,68 @@ int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struc >+ return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v); >+ } >+ >++/* >++ append a int element to a message >++*/ >++int samdb_msg_append_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, >++ const char *attr_name, int v, int flags) >++{ >++ const char *s = talloc_asprintf(mem_ctx, "%d", v); >++ if (s == NULL) { >++ return ldb_oom(sam_ldb); >++ } >++ return ldb_msg_append_string(msg, attr_name, s, flags); >++} >++ >++/* >++ * Append an unsigned int element to a message >++ * >++ * The issue here is that we have not yet first cast to int32_t explicitly, >++ * before we cast to an signed int to printf() into the %d or cast to a >++ * int64_t before we then cast to a long long to printf into a %lld. >++ * >++ * There are *no* unsigned integers in Active Directory LDAP, even the RID >++ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities. >++ * (See the schema, and the syntax definitions in schema_syntax.c). >++ * >++ */ >++int samdb_msg_append_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, >++ const char *attr_name, unsigned int v, int flags) >++{ >++ return samdb_msg_append_int(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags); >++} >++ >++/* >++ append a (signed) int64_t element to a message >++*/ >++int samdb_msg_append_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, >++ const char *attr_name, int64_t v, int flags) >++{ >++ const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v); >++ if (s == NULL) { >++ return ldb_oom(sam_ldb); >++ } >++ return ldb_msg_append_string(msg, attr_name, s, flags); >++} >++ >++/* >++ * Append an unsigned int64_t (uint64_t) element to a message >++ * >++ * The issue here is that we have not yet first cast to int32_t explicitly, >++ * before we cast to an signed int to printf() into the %d or cast to a >++ * int64_t before we then cast to a long long to printf into a %lld. >++ * >++ * There are *no* unsigned integers in Active Directory LDAP, even the RID >++ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities. >++ * (See the schema, and the syntax definitions in schema_syntax.c). >++ * >++ */ >++int samdb_msg_append_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, >++ const char *attr_name, uint64_t v, int flags) >++{ >++ return samdb_msg_append_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v, flags); >++} >++ >+ /* >+ add a samr_Password element to a message >+ */ >+@@ -2814,15 +2892,8 @@ NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, >+ tdo_msg->num_elements = 0; >+ TALLOC_FREE(tdo_msg->elements); >+ >+- ret = ldb_msg_add_empty(tdo_msg, "trustAuthIncoming", >+- LDB_FLAG_MOD_REPLACE, NULL); >+- if (ret != LDB_SUCCESS) { >+- ldb_transaction_cancel(ldb); >+- TALLOC_FREE(frame); >+- return NT_STATUS_NO_MEMORY; >+- } >+- ret = ldb_msg_add_value(tdo_msg, "trustAuthIncoming", >+- &new_val, NULL); >++ ret = ldb_msg_append_value(tdo_msg, "trustAuthIncoming", >++ &new_val, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ ldb_transaction_cancel(ldb); >+ TALLOC_FREE(frame); >+@@ -3187,6 +3258,7 @@ int dsdb_find_guid_by_dn(struct ldb_context *ldb, >+ /* >+ adds the given GUID to the given ldb_message. This value is added >+ for the given attr_name (may be either "objectGUID" or "parentGUID"). >++ This function is used in processing 'add' requests. >+ */ >+ int dsdb_msg_add_guid(struct ldb_message *msg, >+ struct GUID *guid, >+@@ -5656,7 +5728,8 @@ int dsdb_user_obj_set_defaults(struct ldb_context *ldb, >+ } >+ >+ /** >+- * Sets 'sAMAccountType on user object based on userAccountControl >++ * Sets 'sAMAccountType on user object based on userAccountControl. >++ * This function is used in processing both 'add' and 'modify' requests. >+ * @param ldb Current ldb_context >+ * @param usr_obj ldb_message representing User object >+ * @param user_account_control Value for userAccountControl flags >+@@ -5668,21 +5741,19 @@ int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message * >+ { >+ int ret; >+ uint32_t account_type; >+- struct ldb_message_element *el; >+ >+ account_type = ds_uf2atype(user_account_control); >+ if (account_type == 0) { >+ ldb_set_errstring(ldb, "dsdb: Unrecognized account type!"); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+- ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj, >+- "sAMAccountType", >+- account_type); >++ ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj, >++ "sAMAccountType", >++ account_type, >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(usr_obj, "sAMAccountType"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ >+ if (account_type_p) { >+ *account_type_p = account_type; >+@@ -5692,7 +5763,8 @@ int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message * >+ } >+ >+ /** >+- * Determine and set primaryGroupID based on userAccountControl value >++ * Determine and set primaryGroupID based on userAccountControl value. >++ * This function is used in processing both 'add' and 'modify' requests. >+ * @param ldb Current ldb_context >+ * @param usr_obj ldb_message representing User object >+ * @param user_account_control Value for userAccountControl flags >+@@ -5704,17 +5776,15 @@ int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_messa >+ { >+ int ret; >+ uint32_t rid; >+- struct ldb_message_element *el; >+ >+ rid = ds_uf2prim_group_rid(user_account_control); >+ >+- ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj, >+- "primaryGroupID", rid); >++ ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj, >++ "primaryGroupID", rid, >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(usr_obj, "primaryGroupID"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ >+ if (group_rid_p) { >+ *group_rid_p = rid; >+diff --git source4/dsdb/samdb/ldb_modules/descriptor.c source4/dsdb/samdb/ldb_modules/descriptor.c >+index daa08c2ebc7..4b01961dcb0 100644 >+--- source4/dsdb/samdb/ldb_modules/descriptor.c >++++ source4/dsdb/samdb/ldb_modules/descriptor.c >+@@ -857,14 +857,8 @@ static int descriptor_modify(struct ldb_module *module, struct ldb_request *req) >+ return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); >+ } >+ >+- ret = ldb_msg_add_empty(msg, "nTSecurityDescriptor", >+- LDB_FLAG_MOD_REPLACE, >+- &sd_element); >+- if (ret != LDB_SUCCESS) { >+- return ldb_oom(ldb); >+- } >+- ret = ldb_msg_add_value(msg, "nTSecurityDescriptor", >+- sd, NULL); >++ ret = ldb_msg_append_value(msg, "nTSecurityDescriptor", >++ sd, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ldb_oom(ldb); >+ } >+diff --git source4/dsdb/samdb/ldb_modules/objectguid.c source4/dsdb/samdb/ldb_modules/objectguid.c >+index bc3260cf0d8..0fe995a5763 100644 >+--- source4/dsdb/samdb/ldb_modules/objectguid.c >++++ source4/dsdb/samdb/ldb_modules/objectguid.c >+@@ -41,7 +41,6 @@ >+ */ >+ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t) >+ { >+- struct ldb_message_element *el; >+ char *s; >+ int ret; >+ >+@@ -54,16 +53,13 @@ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t) >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+ >+- ret = ldb_msg_add_string(msg, attr, s); >++ /* always set as replace. This works because on add ops, the flag >++ is ignored */ >++ ret = ldb_msg_append_string(msg, attr, s, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+- el = ldb_msg_find_element(msg, attr); >+- /* always set as replace. This works because on add ops, the flag >+- is ignored */ >+- el->flags = LDB_FLAG_MOD_REPLACE; >+- >+ return LDB_SUCCESS; >+ } >+ >+@@ -73,23 +69,19 @@ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t) >+ static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg, >+ const char *attr, uint64_t v) >+ { >+- struct ldb_message_element *el; >+ int ret; >+ >+ if (ldb_msg_find_element(msg, attr) != NULL) { >+ return LDB_SUCCESS; >+ } >+ >+- ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v); >++ /* always set as replace. This works because on add ops, the flag >++ is ignored */ >++ ret = samdb_msg_append_uint64(ldb, msg, msg, attr, v, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+- el = ldb_msg_find_element(msg, attr); >+- /* always set as replace. This works because on add ops, the flag >+- is ignored */ >+- el->flags = LDB_FLAG_MOD_REPLACE; >+- >+ return LDB_SUCCESS; >+ } >+ >+diff --git source4/dsdb/samdb/ldb_modules/partition_init.c source4/dsdb/samdb/ldb_modules/partition_init.c >+index 58c65ccedd0..484b5bffb27 100644 >+--- source4/dsdb/samdb/ldb_modules/partition_init.c >++++ source4/dsdb/samdb/ldb_modules/partition_init.c >+@@ -742,10 +742,6 @@ int partition_create(struct ldb_module *module, struct ldb_request *req) >+ } >+ >+ mod_msg->dn = ldb_dn_new(mod_msg, ldb, DSDB_PARTITION_DN); >+- ret = ldb_msg_add_empty(mod_msg, DSDB_PARTITION_ATTR, LDB_FLAG_MOD_ADD, NULL); >+- if (ret != LDB_SUCCESS) { >+- return ret; >+- } >+ >+ casefold_dn = ldb_dn_get_casefold(dn); >+ >+@@ -785,18 +781,16 @@ int partition_create(struct ldb_module *module, struct ldb_request *req) >+ } >+ partition_record = talloc_asprintf(mod_msg, "%s:%s", casefold_dn, filename); >+ >+- ret = ldb_msg_add_steal_string(mod_msg, DSDB_PARTITION_ATTR, partition_record); >++ ret = ldb_msg_append_steal_string(mod_msg, DSDB_PARTITION_ATTR, partition_record, >++ LDB_FLAG_MOD_ADD); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ if (ldb_request_get_control(req, DSDB_CONTROL_PARTIAL_REPLICA)) { >+ /* this new partition is a partial replica */ >+- ret = ldb_msg_add_empty(mod_msg, "partialReplica", LDB_FLAG_MOD_ADD, NULL); >+- if (ret != LDB_SUCCESS) { >+- return ret; >+- } >+- ret = ldb_msg_add_fmt(mod_msg, "partialReplica", "%s", ldb_dn_get_linearized(dn)); >++ ret = ldb_msg_append_fmt(mod_msg, LDB_FLAG_MOD_ADD, >++ "partialReplica", "%s", ldb_dn_get_linearized(dn)); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+diff --git source4/dsdb/samdb/ldb_modules/repl_meta_data.c source4/dsdb/samdb/ldb_modules/repl_meta_data.c >+index 29ffda75c87..eec1e639856 100644 >+--- source4/dsdb/samdb/ldb_modules/repl_meta_data.c >++++ source4/dsdb/samdb/ldb_modules/repl_meta_data.c >+@@ -3888,22 +3888,12 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are >+ ldb_operr(ldb)); >+ } >+ >+- if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { >++ if (ldb_msg_append_value(msg, rdn_name, rdn_val, LDB_FLAG_MOD_REPLACE) != 0) { >+ talloc_free(ares); >+ return ldb_module_done(ac->req, NULL, NULL, >+ ldb_oom(ldb)); >+ } >+- if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) { >+- talloc_free(ares); >+- return ldb_module_done(ac->req, NULL, NULL, >+- ldb_oom(ldb)); >+- } >+- if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { >+- talloc_free(ares); >+- return ldb_module_done(ac->req, NULL, NULL, >+- ldb_oom(ldb)); >+- } >+- if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) { >++ if (ldb_msg_append_value(msg, "name", rdn_val, LDB_FLAG_MOD_REPLACE) != 0) { >+ talloc_free(ares); >+ return ldb_module_done(ac->req, NULL, NULL, >+ ldb_oom(ldb)); >+@@ -5161,16 +5151,10 @@ static int replmd_name_modify(struct replmd_replicated_request *ar, >+ goto failed; >+ } >+ >+- if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { >+- goto failed; >+- } >+- if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) { >+- goto failed; >+- } >+- if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { >++ if (ldb_msg_append_value(msg, rdn_name, rdn_val, LDB_FLAG_MOD_REPLACE) != 0) { >+ goto failed; >+ } >+- if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) { >++ if (ldb_msg_append_value(msg, "name", rdn_val, LDB_FLAG_MOD_REPLACE) != 0) { >+ goto failed; >+ } >+ >+diff --git source4/dsdb/samdb/ldb_modules/samldb.c source4/dsdb/samdb/ldb_modules/samldb.c >+index 5fb9c195c9a..107e643e492 100644 >+--- source4/dsdb/samdb/ldb_modules/samldb.c >++++ source4/dsdb/samdb/ldb_modules/samldb.c >+@@ -1103,14 +1103,11 @@ static int samldb_rodc_add(struct samldb_ctx *ac) >+ return LDB_ERR_OTHER; >+ >+ found: >+- ret = ldb_msg_add_empty(ac->msg, "msDS-SecondaryKrbTgtNumber", >+- LDB_FLAG_INTERNAL_DISABLE_VALIDATION, NULL); >+- if (ret != LDB_SUCCESS) { >+- return ldb_operr(ldb); >+- } >+ >+- ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, >+- "msDS-SecondaryKrbTgtNumber", krbtgt_number); >++ ldb_msg_remove_attr(ac->msg, "msDS-SecondaryKrbTgtNumber"); >++ ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg, >++ "msDS-SecondaryKrbTgtNumber", krbtgt_number, >++ LDB_FLAG_INTERNAL_DISABLE_VALIDATION); >+ if (ret != LDB_SUCCESS) { >+ return ldb_operr(ldb); >+ } >+@@ -1792,7 +1789,7 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) >+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); >+ void *skip_allocate_sids = ldb_get_opaque(ldb, >+ "skip_allocate_sids"); >+- struct ldb_message_element *el, *el2; >++ struct ldb_message_element *el; >+ struct dom_sid *sid; >+ int ret; >+ >+@@ -1926,23 +1923,17 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) >+ /* "isCriticalSystemObject" might be set */ >+ if (user_account_control & >+ (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) { >+- ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", >+- "TRUE"); >++ ret = ldb_msg_add_string_flags(ac->msg, "isCriticalSystemObject", >++ "TRUE", LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el2 = ldb_msg_find_element(ac->msg, >+- "isCriticalSystemObject"); >+- el2->flags = LDB_FLAG_MOD_REPLACE; >+ } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) { >+- ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", >+- "FALSE"); >++ ret = ldb_msg_add_string_flags(ac->msg, "isCriticalSystemObject", >++ "FALSE", LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el2 = ldb_msg_find_element(ac->msg, >+- "isCriticalSystemObject"); >+- el2->flags = LDB_FLAG_MOD_REPLACE; >+ } >+ >+ /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */ >+@@ -2018,14 +2009,13 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) >+ ldb_set_errstring(ldb, "samldb: Unrecognized account type!"); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+- ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, >+- "sAMAccountType", >+- account_type); >++ ret = samdb_msg_add_uint_flags(ldb, ac->msg, ac->msg, >++ "sAMAccountType", >++ account_type, >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el2 = ldb_msg_find_element(ac->msg, "sAMAccountType"); >+- el2->flags = LDB_FLAG_MOD_REPLACE; >+ } >+ break; >+ } >+@@ -2945,26 +2935,23 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) >+ } >+ >+ if (old_atype != new_atype) { >+- ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, >+- "sAMAccountType", new_atype); >++ ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg, >++ "sAMAccountType", new_atype, >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(ac->msg, "sAMAccountType"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ } >+ >+ /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */ >+ if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) { >+ /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */ >+ ldb_msg_remove_attr(ac->msg, "lockoutTime"); >+- ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime", >+- (NTTIME)0); >++ ret = samdb_msg_append_uint64(ldb, ac->msg, ac->msg, "lockoutTime", >++ (NTTIME)0, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(ac->msg, "lockoutTime"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ } >+ >+ /* >+@@ -2975,14 +2962,12 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) >+ * creating the attribute. >+ */ >+ if (old_is_critical != new_is_critical || old_atype != new_atype) { >+- ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", >+- new_is_critical ? "TRUE": "FALSE"); >++ ret = ldb_msg_append_string(ac->msg, "isCriticalSystemObject", >++ new_is_critical ? "TRUE": "FALSE", >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(ac->msg, >+- "isCriticalSystemObject"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ } >+ >+ if (!ldb_msg_find_element(ac->msg, "primaryGroupID") && >+@@ -2995,14 +2980,12 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) >+ } >+ } >+ >+- ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, >+- "primaryGroupID", new_pgrid); >++ ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg, >++ "primaryGroupID", new_pgrid, >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(ac->msg, >+- "primaryGroupID"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ } >+ >+ /* Propagate eventual "userAccountControl" attribute changes */ >+@@ -3205,13 +3188,12 @@ static int samldb_lockout_time(struct samldb_ctx *ac) >+ >+ /* lockoutTime == 0 resets badPwdCount */ >+ ldb_msg_remove_attr(ac->msg, "badPwdCount"); >+- ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, >+- "badPwdCount", 0); >++ ret = samdb_msg_append_int(ldb, ac->msg, ac->msg, >++ "badPwdCount", 0, >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(ac->msg, "badPwdCount"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ >+ return LDB_SUCCESS; >+ } >+@@ -3309,13 +3291,11 @@ static int samldb_group_type_change(struct samldb_ctx *ac) >+ ldb_set_errstring(ldb, "samldb: Unrecognized account type!"); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+- ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType", >+- account_type); >++ ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg, "sAMAccountType", >++ account_type, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(ac->msg, "sAMAccountType"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ >+ return LDB_SUCCESS; >+ } >+diff --git source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c >+index 5f8911c66be..99c5955e9e7 100644 >+--- source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c >++++ source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c >+@@ -294,14 +294,13 @@ static int tr_prepare_attributes(struct tr_context *ac) >+ return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM, >+ "reanimate: Unrecognized account type!"); >+ } >+- ret = samdb_msg_add_uint(ldb, ac->mod_msg, ac->mod_msg, >+- "sAMAccountType", account_type); >++ ret = samdb_msg_append_uint(ldb, ac->mod_msg, ac->mod_msg, >++ "sAMAccountType", account_type, >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, >+ "reanimate: Failed to add sAMAccountType to restored object."); >+ } >+- el = ldb_msg_find_element(ac->mod_msg, "sAMAccountType"); >+- el->flags = LDB_FLAG_MOD_REPLACE; >+ >+ /* Default values set by Windows */ >+ ret = samdb_find_or_add_attribute(ldb, ac->mod_msg, >+@@ -324,12 +323,11 @@ static int tr_prepare_attributes(struct tr_context *ac) >+ return ret; >+ } >+ >+- ret = ldb_msg_add_string(ac->mod_msg, "objectCategory", value); >++ ret = ldb_msg_append_string(ac->mod_msg, "objectCategory", value, >++ LDB_FLAG_MOD_ADD); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+- el = ldb_msg_find_element(ac->mod_msg, "objectCategory"); >+- el->flags = LDB_FLAG_MOD_ADD; >+ } >+ >+ return LDB_SUCCESS; >+diff --git source4/nbt_server/wins/winsdb.c source4/nbt_server/wins/winsdb.c >+index e4a7c2042ed..2a05e96bca4 100644 >+--- source4/nbt_server/wins/winsdb.c >++++ source4/nbt_server/wins/winsdb.c >+@@ -102,13 +102,11 @@ uint64_t winsdb_set_maxVersion(struct winsdb_handle *h, uint64_t newMaxVersion) >+ msg->dn = dn; >+ >+ >+- ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL); >++ ret = ldb_msg_append_string(msg, "objectClass", "winsMaxVersion", >++ LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) goto failed; >+- ret = ldb_msg_add_string(msg, "objectClass", "winsMaxVersion"); >+- if (ret != LDB_SUCCESS) goto failed; >+- ret = ldb_msg_add_empty(msg, "maxVersion", LDB_FLAG_MOD_REPLACE, NULL); >+- if (ret != LDB_SUCCESS) goto failed; >+- ret = ldb_msg_add_fmt(msg, "maxVersion", "%llu", (long long)newMaxVersion); >++ ret = ldb_msg_append_fmt(msg, LDB_FLAG_MOD_REPLACE, >++ "maxVersion", "%llu", (long long)newMaxVersion); >+ if (ret != LDB_SUCCESS) goto failed; >+ >+ ret = ldb_modify(wins_db, msg); >+@@ -779,8 +777,7 @@ static struct ldb_message *winsdb_message(struct ldb_context *ldb, >+ ret |= ldb_msg_add_winsdb_addr(msg, rec, "address", rec->addresses[i]); >+ } >+ if (rec->registered_by) { >+- ret |= ldb_msg_add_empty(msg, "registeredBy", 0, NULL); >+- ret |= ldb_msg_add_string(msg, "registeredBy", rec->registered_by); >++ ret |= ldb_msg_append_string(msg, "registeredBy", rec->registered_by, 0); >+ } >+ if (ret != LDB_SUCCESS) goto failed; >+ return msg; >+diff --git source4/rpc_server/lsa/dcesrv_lsa.c source4/rpc_server/lsa/dcesrv_lsa.c >+index 15b068aec62..a165ab2b9d6 100644 >+--- source4/rpc_server/lsa/dcesrv_lsa.c >++++ source4/rpc_server/lsa/dcesrv_lsa.c >+@@ -1778,12 +1778,7 @@ static NTSTATUS update_uint32_t_value(TALLOC_CTX *mem_ctx, >+ goto done; >+ } >+ >+- ret = ldb_msg_add_empty(dest, attribute, flags, NULL); >+- if (ret != LDB_SUCCESS) { >+- return NT_STATUS_NO_MEMORY; >+- } >+- >+- ret = samdb_msg_add_uint(sam_ldb, dest, dest, attribute, value); >++ ret = samdb_msg_append_uint(sam_ldb, dest, dest, attribute, value, flags); >+ if (ret != LDB_SUCCESS) { >+ return NT_STATUS_NO_MEMORY; >+ } >+@@ -1874,13 +1869,7 @@ static NTSTATUS update_trust_user(TALLOC_CTX *mem_ctx, >+ continue; >+ } >+ >+- ret = ldb_msg_add_empty(msg, attribute, >+- LDB_FLAG_MOD_REPLACE, NULL); >+- if (ret != LDB_SUCCESS) { >+- return NT_STATUS_NO_MEMORY; >+- } >+- >+- ret = ldb_msg_add_value(msg, attribute, &v, NULL); >++ ret = ldb_msg_append_value(msg, attribute, &v, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ return NT_STATUS_NO_MEMORY; >+ } >+@@ -2166,28 +2155,30 @@ static NTSTATUS setInfoTrustedDomain_base(struct dcesrv_call_state *dce_call, >+ } >+ >+ if (add_incoming || del_incoming) { >+- ret = ldb_msg_add_empty(msg, "trustAuthIncoming", >+- LDB_FLAG_MOD_REPLACE, NULL); >+- if (ret != LDB_SUCCESS) { >+- return NT_STATUS_NO_MEMORY; >+- } >+ if (add_incoming) { >+- ret = ldb_msg_add_value(msg, "trustAuthIncoming", >+- &trustAuthIncoming, NULL); >++ ret = ldb_msg_append_value(msg, "trustAuthIncoming", >++ &trustAuthIncoming, LDB_FLAG_MOD_REPLACE); >++ if (ret != LDB_SUCCESS) { >++ return NT_STATUS_NO_MEMORY; >++ } >++ } else { >++ ret = ldb_msg_add_empty(msg, "trustAuthIncoming", >++ LDB_FLAG_MOD_REPLACE, NULL); >+ if (ret != LDB_SUCCESS) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ } >+ } >+ if (add_outgoing || del_outgoing) { >+- ret = ldb_msg_add_empty(msg, "trustAuthOutgoing", >+- LDB_FLAG_MOD_REPLACE, NULL); >+- if (ret != LDB_SUCCESS) { >+- return NT_STATUS_NO_MEMORY; >+- } >+ if (add_outgoing) { >+- ret = ldb_msg_add_value(msg, "trustAuthOutgoing", >+- &trustAuthOutgoing, NULL); >++ ret = ldb_msg_append_value(msg, "trustAuthOutgoing", >++ &trustAuthOutgoing, LDB_FLAG_MOD_REPLACE); >++ if (ret != LDB_SUCCESS) { >++ return NT_STATUS_NO_MEMORY; >++ } >++ } else { >++ ret = ldb_msg_add_empty(msg, "trustAuthOutgoing", >++ LDB_FLAG_MOD_REPLACE, NULL); >+ if (ret != LDB_SUCCESS) { >+ return NT_STATUS_NO_MEMORY; >+ } >+@@ -4635,14 +4626,8 @@ static NTSTATUS dcesrv_lsa_lsaRSetForestTrustInformation(struct dcesrv_call_stat >+ goto done; >+ } >+ >+- ret = ldb_msg_add_empty(msg, "msDS-TrustForestTrustInfo", >+- LDB_FLAG_MOD_REPLACE, NULL); >+- if (ret != LDB_SUCCESS) { >+- status = NT_STATUS_NO_MEMORY; >+- goto done; >+- } >+- ret = ldb_msg_add_value(msg, "msDS-TrustForestTrustInfo", >+- &ft_blob, NULL); >++ ret = ldb_msg_append_value(msg, "msDS-TrustForestTrustInfo", >++ &ft_blob, LDB_FLAG_MOD_REPLACE); >+ if (ret != LDB_SUCCESS) { >+ status = NT_STATUS_NO_MEMORY; >+ goto done; >+diff --git source4/winbind/idmap.c source4/winbind/idmap.c >+index c4039be473a..c6375f8357a 100644 >+--- source4/winbind/idmap.c >++++ source4/winbind/idmap.c >+@@ -672,14 +672,8 @@ static NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, >+ vals[1].data = (uint8_t *)hwm_string; >+ vals[1].length = strlen(hwm_string); >+ } else { >+- ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD, >+- NULL); >+- if (ret != LDB_SUCCESS) { >+- status = NT_STATUS_NONE_MAPPED; >+- goto failed; >+- } >+- >+- ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string); >++ ret = ldb_msg_append_string(hwm_msg, "xidNumber", hwm_string, >++ LDB_FLAG_MOD_ADD); >+ if (ret != LDB_SUCCESS) >+ { >+ status = NT_STATUS_NONE_MAPPED; >+-- >+2.25.1 >+ >+ >+From 7270b68386692829f97d5c51c50108db395b263e Mon Sep 17 00:00:00 2001 >+From: Andrew Bartlett <abartlet@samba.org> >+Date: Tue, 14 Jun 2022 15:43:26 +1200 >+Subject: [PATCH 14/99] CVE-2022-32746 ldb: Release LDB 2.3.4 >+ >+* CVE-2022-32746 Use-after-free occurring in database audit logging module (bug 15009) >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15009 >+ >+Signed-off-by: Andrew Bartlett <abartlet@samba.org> >+--- >+ lib/ldb/ABI/ldb-2.3.4.sigs | 291 ++++++++++++++++++++++++++++++ >+ lib/ldb/ABI/pyldb-util-2.3.4.sigs | 3 + >+ lib/ldb/wscript | 2 +- >+ 3 files changed, 295 insertions(+), 1 deletion(-) >+ create mode 100644 lib/ldb/ABI/ldb-2.3.4.sigs >+ create mode 100644 lib/ldb/ABI/pyldb-util-2.3.4.sigs >+ >+diff --git lib/ldb/ABI/ldb-2.3.4.sigs lib/ldb/ABI/ldb-2.3.4.sigs >+new file mode 100644 >+index 00000000000..40388d9e330 >+--- /dev/null >++++ lib/ldb/ABI/ldb-2.3.4.sigs >+@@ -0,0 +1,291 @@ >++ldb_add: int (struct ldb_context *, const struct ldb_message *) >++ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *) >++ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...) >++ldb_attr_casefold: char *(TALLOC_CTX *, const char *) >++ldb_attr_dn: int (const char *) >++ldb_attr_in_list: int (const char * const *, const char *) >++ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *) >++ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *) >++ldb_base64_decode: int (char *) >++ldb_base64_encode: char *(TALLOC_CTX *, const char *, int) >++ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *) >++ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val) >++ldb_binary_encode_string: char *(TALLOC_CTX *, const char *) >++ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >++ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >++ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >++ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >++ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >++ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >++ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >++ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t) >++ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t) >++ldb_check_critical_controls: int (struct ldb_control **) >++ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) >++ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) >++ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **) >++ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *) >++ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *) >++ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) >++ldb_debug_add: void (struct ldb_context *, const char *, ...) >++ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level) >++ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) >++ldb_delete: int (struct ldb_context *, struct ldb_dn *) >++ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *) >++ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...) >++ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *) >++ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...) >++ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val) >++ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *) >++ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *) >++ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *) >++ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *) >++ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *) >++ldb_dn_check_special: bool (struct ldb_dn *, const char *) >++ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *) >++ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *) >++ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) >++ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val) >++ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *) >++ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *) >++ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *) >++ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *) >++ldb_dn_get_casefold: const char *(struct ldb_dn *) >++ldb_dn_get_comp_num: int (struct ldb_dn *) >++ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int) >++ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int) >++ldb_dn_get_extended_comp_num: int (struct ldb_dn *) >++ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *) >++ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int) >++ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *) >++ldb_dn_get_linearized: const char *(struct ldb_dn *) >++ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) >++ldb_dn_get_rdn_name: const char *(struct ldb_dn *) >++ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *) >++ldb_dn_has_extended: bool (struct ldb_dn *) >++ldb_dn_is_null: bool (struct ldb_dn *) >++ldb_dn_is_special: bool (struct ldb_dn *) >++ldb_dn_is_valid: bool (struct ldb_dn *) >++ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) >++ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) >++ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) >++ldb_dn_minimise: bool (struct ldb_dn *) >++ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *) >++ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...) >++ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int) >++ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int) >++ldb_dn_remove_extended_components: void (struct ldb_dn *) >++ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *) >++ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val) >++ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *) >++ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *) >++ldb_dn_validate: bool (struct ldb_dn *) >++ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *) >++ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int) >++ldb_errstring: const char *(struct ldb_context *) >++ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **) >++ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *) >++ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *) >++ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *) >++ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *) >++ldb_get_create_perms: unsigned int (struct ldb_context *) >++ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *) >++ldb_get_event_context: struct tevent_context *(struct ldb_context *) >++ldb_get_flags: unsigned int (struct ldb_context *) >++ldb_get_opaque: void *(struct ldb_context *, const char *) >++ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *) >++ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *) >++ldb_global_init: int (void) >++ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *) >++ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *) >++ldb_handle_use_global_event_context: void (struct ldb_handle *) >++ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) >++ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) >++ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *) >++ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) >++ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) >++ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **) >++ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *) >++ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *) >++ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *) >++ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *) >++ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **) >++ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *) >++ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *) >++ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) >++ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) >++ldb_load_modules: int (struct ldb_context *, const char **) >++ldb_map_add: int (struct ldb_module *, struct ldb_request *) >++ldb_map_delete: int (struct ldb_module *, struct ldb_request *) >++ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *) >++ldb_map_modify: int (struct ldb_module *, struct ldb_request *) >++ldb_map_rename: int (struct ldb_module *, struct ldb_request *) >++ldb_map_search: int (struct ldb_module *, struct ldb_request *) >++ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *) >++ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope) >++ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *) >++ldb_match_msg_objectclass: int (const struct ldb_message *, const char *) >++ldb_mod_register_control: int (struct ldb_module *, const char *) >++ldb_modify: int (struct ldb_context *, const struct ldb_message *) >++ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *) >++ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *) >++ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **) >++ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int) >++ldb_module_flags: uint32_t (struct ldb_context *) >++ldb_module_get_ctx: struct ldb_context *(struct ldb_module *) >++ldb_module_get_name: const char *(struct ldb_module *) >++ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *) >++ldb_module_get_private: void *(struct ldb_module *) >++ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *) >++ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **) >++ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *) >++ldb_module_next: struct ldb_module *(struct ldb_module *) >++ldb_module_popt_options: struct poptOption **(struct ldb_context *) >++ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **) >++ldb_module_send_referral: int (struct ldb_request *, char *) >++ldb_module_set_next: void (struct ldb_module *, struct ldb_module *) >++ldb_module_set_private: void (struct ldb_module *, void *) >++ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type) >++ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *) >++ldb_modules_load: int (const char *, const char *) >++ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int) >++ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **) >++ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...) >++ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *) >++ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *) >++ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *) >++ldb_msg_add_string: int (struct ldb_message *, const char *, const char *) >++ldb_msg_add_string_flags: int (struct ldb_message *, const char *, const char *, int) >++ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **) >++ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...) >++ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int) >++ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int) >++ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int) >++ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int) >++ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int) >++ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *) >++ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *) >++ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) >++ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *) >++ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) >++ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *) >++ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **) >++ldb_msg_element_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *) >++ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *) >++ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *) >++ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *) >++ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int) >++ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *) >++ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double) >++ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int) >++ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t) >++ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *) >++ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int) >++ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t) >++ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t) >++ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t) >++ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *) >++ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *) >++ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *) >++ldb_msg_new: struct ldb_message *(TALLOC_CTX *) >++ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **) >++ldb_msg_remove_attr: void (struct ldb_message *, const char *) >++ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *) >++ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *) >++ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *) >++ldb_msg_sort_elements: void (struct ldb_message *) >++ldb_next_del_trans: int (struct ldb_module *) >++ldb_next_end_trans: int (struct ldb_module *) >++ldb_next_init: int (struct ldb_module *) >++ldb_next_prepare_commit: int (struct ldb_module *) >++ldb_next_read_lock: int (struct ldb_module *) >++ldb_next_read_unlock: int (struct ldb_module *) >++ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *) >++ldb_next_request: int (struct ldb_module *, struct ldb_request *) >++ldb_next_start_trans: int (struct ldb_module *) >++ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *) >++ldb_options_copy: const char **(TALLOC_CTX *, const char **) >++ldb_options_find: const char *(struct ldb_context *, const char **, const char *) >++ldb_options_get: const char **(struct ldb_context *) >++ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t) >++ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *) >++ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **) >++ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *) >++ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *) >++ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *) >++ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *) >++ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t) >++ldb_register_backend: int (const char *, ldb_connect_fn, bool) >++ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *) >++ldb_register_hook: int (ldb_hook_fn) >++ldb_register_module: int (const struct ldb_module_ops *) >++ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *) >++ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *) >++ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *) >++ldb_req_get_custom_flags: uint32_t (struct ldb_request *) >++ldb_req_is_untrusted: bool (struct ldb_request *) >++ldb_req_location: const char *(struct ldb_request *) >++ldb_req_mark_trusted: void (struct ldb_request *) >++ldb_req_mark_untrusted: void (struct ldb_request *) >++ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t) >++ldb_req_set_location: void (struct ldb_request *, const char *) >++ldb_request: int (struct ldb_context *, struct ldb_request *) >++ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *) >++ldb_request_done: int (struct ldb_request *, int) >++ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *) >++ldb_request_get_status: int (struct ldb_request *) >++ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *) >++ldb_request_set_state: void (struct ldb_request *, int) >++ldb_reset_err_string: void (struct ldb_context *) >++ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***) >++ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *) >++ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *) >++ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *) >++ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *) >++ldb_schema_attribute_remove: void (struct ldb_context *, const char *) >++ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int) >++ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *) >++ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *) >++ldb_schema_set_override_indexlist: void (struct ldb_context *, bool) >++ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...) >++ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *) >++ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *) >++ldb_set_create_perms: void (struct ldb_context *, unsigned int) >++ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *) >++ldb_set_debug_stderr: int (struct ldb_context *) >++ldb_set_default_dns: void (struct ldb_context *) >++ldb_set_errstring: void (struct ldb_context *, const char *) >++ldb_set_event_context: void (struct ldb_context *, struct tevent_context *) >++ldb_set_flags: void (struct ldb_context *, unsigned int) >++ldb_set_modules_dir: void (struct ldb_context *, const char *) >++ldb_set_opaque: int (struct ldb_context *, const char *, void *) >++ldb_set_require_private_event_context: void (struct ldb_context *) >++ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int) >++ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *) >++ldb_set_utf8_default: void (struct ldb_context *) >++ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t)) >++ldb_setup_wellknown_attributes: int (struct ldb_context *) >++ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *) >++ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *) >++ldb_strerror: const char *(int) >++ldb_string_to_time: time_t (const char *) >++ldb_string_utc_to_time: time_t (const char *) >++ldb_timestring: char *(TALLOC_CTX *, time_t) >++ldb_timestring_utc: char *(TALLOC_CTX *, time_t) >++ldb_transaction_cancel: int (struct ldb_context *) >++ldb_transaction_cancel_noerr: int (struct ldb_context *) >++ldb_transaction_commit: int (struct ldb_context *) >++ldb_transaction_prepare_commit: int (struct ldb_context *) >++ldb_transaction_start: int (struct ldb_context *) >++ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *) >++ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int) >++ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *) >++ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *) >++ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *) >++ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) >++ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) >++ldb_val_string_cmp: int (const struct ldb_val *, const char *) >++ldb_val_to_time: int (const struct ldb_val *, time_t *) >++ldb_valid_attr_name: int (const char *) >++ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list) >++ldb_wait: int (struct ldb_handle *, enum ldb_wait_type) >+diff --git lib/ldb/ABI/pyldb-util-2.3.4.sigs lib/ldb/ABI/pyldb-util-2.3.4.sigs >+new file mode 100644 >+index 00000000000..164a806b2ff >+--- /dev/null >++++ lib/ldb/ABI/pyldb-util-2.3.4.sigs >+@@ -0,0 +1,3 @@ >++pyldb_Dn_FromDn: PyObject *(struct ldb_dn *) >++pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **) >++pyldb_check_type: bool (PyObject *, const char *) >+ >+-- >+2.25.1 >+ >+ >+From 6237c85565332e0be1890dd57cc7e25fb76571d7 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Wed, 16 Feb 2022 17:03:10 +1300 >+Subject: [PATCH 15/99] CVE-2022-32745 s4/dsdb/samldb: Check for empty values >+ array >+ >+This avoids potentially trying to access the first element of an empty >+array. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/samldb.c | 4 ++-- >+ 1 file changed, 2 insertions(+), 2 deletions(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/samldb.c source4/dsdb/samdb/ldb_modules/samldb.c >+index 107e643e492..3625bb42e58 100644 >+--- source4/dsdb/samdb/ldb_modules/samldb.c >++++ source4/dsdb/samdb/ldb_modules/samldb.c >+@@ -751,7 +751,7 @@ static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac) >+ return ret; >+ } >+ >+- if (el == NULL) { >++ if (el == NULL || el->num_values == 0) { >+ return LDB_SUCCESS; >+ } >+ >+@@ -919,7 +919,7 @@ static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac) >+ return ret; >+ } >+ >+- if (el == NULL) { >++ if (el == NULL || el->num_values == 0) { >+ return LDB_SUCCESS; >+ } >+ >+-- >+2.25.1 >+ >+ >+From 7c8427e5d2f247921ab44996829acfed1f5f2360 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Thu, 17 Feb 2022 11:11:53 +1300 >+Subject: [PATCH 16/99] CVE-2022-32745 s4/dsdb/util: Use correct value for loop >+ count limit >+ >+Currently, we can crash the server by sending a large number of values >+of a specific attribute (such as sAMAccountName) spread across a few >+message elements. If val_count is larger than the total number of >+elements, we get an access beyond the elements array. >+ >+Similarly, we can include unrelated message elements prior to the >+message elements of the attribute in question, so that not all of the >+attribute's values are copied into the returned elements values array. >+This can cause the server to access uninitialised data, likely resulting >+in a crash or unexpected behaviour. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/util.c | 2 +- >+ 1 file changed, 1 insertion(+), 1 deletion(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/util.c source4/dsdb/samdb/ldb_modules/util.c >+index 405febf0b3d..14947746837 100644 >+--- source4/dsdb/samdb/ldb_modules/util.c >++++ source4/dsdb/samdb/ldb_modules/util.c >+@@ -1546,7 +1546,7 @@ int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx, >+ >+ v = _el->values; >+ >+- for (i = 0; i < val_count; i++) { >++ for (i = 0; i < msg->num_elements; i++) { >+ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) { >+ if ((operation == LDB_MODIFY) && >+ (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) >+-- >+2.25.1 >+ >+ >+From 4d2d30c21b16a53d5547cb803efe49cb6304ce37 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Thu, 17 Feb 2022 11:13:38 +1300 >+Subject: [PATCH 17/99] CVE-2022-32745 s4/dsdb/util: Don't call memcpy() with a >+ NULL pointer >+ >+Doing so is undefined behaviour. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/util.c | 12 ++++++++---- >+ 1 file changed, 8 insertions(+), 4 deletions(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/util.c source4/dsdb/samdb/ldb_modules/util.c >+index 14947746837..35ae110b5ef 100644 >+--- source4/dsdb/samdb/ldb_modules/util.c >++++ source4/dsdb/samdb/ldb_modules/util.c >+@@ -1548,15 +1548,19 @@ int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx, >+ >+ for (i = 0; i < msg->num_elements; i++) { >+ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) { >++ const struct ldb_message_element *tmp_el = &msg->elements[i]; >+ if ((operation == LDB_MODIFY) && >+- (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) >++ (LDB_FLAG_MOD_TYPE(tmp_el->flags) >+ == LDB_FLAG_MOD_DELETE)) { >+ continue; >+ } >++ if (tmp_el->values == NULL || tmp_el->num_values == 0) { >++ continue; >++ } >+ memcpy(v, >+- msg->elements[i].values, >+- msg->elements[i].num_values); >+- v += msg->elements[i].num_values; >++ tmp_el->values, >++ tmp_el->num_values); >++ v += tmp_el->num_values; >+ } >+ } >+ >+-- >+2.25.1 >+ >+ >+From 65d96369fa4f915f01e203cfc8b15e48c5b4b440 Mon Sep 17 00:00:00 2001 >+From: Joseph Sutton <josephsutton@catalyst.net.nz> >+Date: Fri, 3 Jun 2022 16:16:31 +1200 >+Subject: [PATCH 18/99] CVE-2022-32745 s4/dsdb/util: Correctly copy values into >+ message element >+ >+To use memcpy(), we need to specify the number of bytes to copy, rather >+than the number of ldb_val structures. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15008 >+ >+Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >+--- >+ source4/dsdb/samdb/ldb_modules/util.c | 2 +- >+ 1 file changed, 1 insertion(+), 1 deletion(-) >+ >+diff --git source4/dsdb/samdb/ldb_modules/util.c source4/dsdb/samdb/ldb_modules/util.c >+index 35ae110b5ef..e7fe8f855df 100644 >+--- source4/dsdb/samdb/ldb_modules/util.c >++++ source4/dsdb/samdb/ldb_modules/util.c >+@@ -1559,7 +1559,7 @@ int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx, >+ } >+ memcpy(v, >+ tmp_el->values, >+- tmp_el->num_values); >++ tmp_el->num_values * sizeof(*v)); >+ v += tmp_el->num_values; >+ } >+ } >+-- >+2.25.1 >+ >+ >+From 34eb92a2066cc403aac5a3708257b04a40ba19ee 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) >+ >+[jsutton@samba.org Removed MIT knownfail changes] >+--- >+ source4/heimdal/lib/hdb/hdb.h | 1 + >+ source4/kdc/db-glue.c | 7 ++++++- >+ source4/kdc/mit_samba.c | 8 ++++++++ >+ source4/kdc/sdb.h | 1 + >+ 4 files changed, 16 insertions(+), 1 deletion(-) >+ >+diff --git source4/heimdal/lib/hdb/hdb.h source4/heimdal/lib/hdb/hdb.h >+index 5ef9d9565f3..dafaffc6c2d 100644 >+--- source4/heimdal/lib/hdb/hdb.h >++++ 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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index 3a7e2176653..ac47fe78373 100644 >+--- source4/kdc/db-glue.c >++++ 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 source4/kdc/mit_samba.c source4/kdc/mit_samba.c >+index e015c5a52db..c2a604045d9 100644 >+--- source4/kdc/mit_samba.c >++++ source4/kdc/mit_samba.c >+@@ -195,6 +195,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 source4/kdc/sdb.h source4/kdc/sdb.h >+index c929acccce6..a9115ec23d7 100644 >+--- source4/kdc/sdb.h >++++ 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 06a0a75b16bace9c29568653d9e4bde4050c5ee5 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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index ac47fe78373..d017741e30a 100644 >+--- source4/kdc/db-glue.c >++++ 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 b4005403032b0b33ca88d3abcbf085621b32bd5b 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 source4/dsdb/tests/python/priv_attrs.py source4/dsdb/tests/python/priv_attrs.py >+index aa35dcc1317..4dfdfb9cbb8 100644 >+--- source4/dsdb/tests/python/priv_attrs.py >++++ 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 6a4ed078902dcc57ab14f701c88e76ec0ac375e7 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index 42f2e94f5aa..36a6134e6c9 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 837453d34799f44653d0d6d690d3e3d5eb074993 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 python/samba/tests/krb5/as_req_tests.py python/samba/tests/krb5/as_req_tests.py >+index 08081928363..315720f85d6 100755 >+--- python/samba/tests/krb5/as_req_tests.py >++++ 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 python/samba/tests/krb5/salt_tests.py python/samba/tests/krb5/salt_tests.py >+index ecbf618e40e..db777f8b7bc 100755 >+--- python/samba/tests/krb5/salt_tests.py >++++ 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 3d48ade670bb5b026d7bc0a26a4fa6775b21653b 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 python/samba/tests/krb5/test_rpc.py python/samba/tests/krb5/test_rpc.py >+index 03c125f518a..2d483986e83 100755 >+--- python/samba/tests/krb5/test_rpc.py >++++ 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 bf1aa0927895b1007ecea738681235b5be2e6208 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index 36a6134e6c9..da3f69c79c6 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 651db77b1c19c036cf229c44b764b0155e1dc399 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index abac5a47a56..0578969ba69 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 1e9ad4246ce7fe7a212da4357e6e11c5ac22a8b2 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) >+ >+[jsutton@samba.org Fixed MIT knownfail conflict] >+--- >+ 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 | 9 ++ >+ 7 files changed, 181 insertions(+), 133 deletions(-) >+ >+diff --git python/samba/tests/krb5/alias_tests.py python/samba/tests/krb5/alias_tests.py >+index 60213845a44..1f63775c189 100755 >+--- python/samba/tests/krb5/alias_tests.py >++++ 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 0578969ba69..7ea15f0fbab 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py >+index 0aa3309b814..e6b90d3e16a 100755 >+--- python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py >++++ 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 python/samba/tests/krb5/s4u_tests.py python/samba/tests/krb5/s4u_tests.py >+index a80a7b3427e..5f37525f393 100755 >+--- python/samba/tests/krb5/s4u_tests.py >++++ 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 python/samba/tests/krb5/test_rpc.py python/samba/tests/krb5/test_rpc.py >+index 2d483986e83..5a3c7339cea 100755 >+--- python/samba/tests/krb5/test_rpc.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 7eba899966e..1b7e159c381 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -233,16 +233,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 >+@@ -259,3 +264,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 8cd36fe2d96..cc12499bb50 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -390,6 +390,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 >+@@ -401,6 +403,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_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 >+@@ -418,6 +422,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 >+@@ -427,6 +432,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 >+@@ -462,6 +469,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 ea82822a5c451df50feed15c5da3501df2b5c106 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 7ea15f0fbab..6160ef649e8 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 eb0ed5f4f6d725c49fda97bc8f7aae89f90bd913 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) >+ >+[jsutton@samba.org Removed some MIT knownfail changes] >+--- >+ python/samba/tests/krb5/kdc_tgs_tests.py | 16 ++++++++++++++++ >+ python/samba/tests/krb5/rfc4120_constants.py | 1 + >+ selftest/knownfail_mit_kdc | 1 + >+ 3 files changed, 18 insertions(+) >+ >+diff --git python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 6160ef649e8..f5f091610ac 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 python/samba/tests/krb5/rfc4120_constants.py python/samba/tests/krb5/rfc4120_constants.py >+index 5251e291fde..a9fdc5735dd 100644 >+--- python/samba/tests/krb5/rfc4120_constants.py >++++ 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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index cc12499bb50..3aacec00870 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -422,6 +422,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_invalid >+ ^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 >+-- >+2.25.1 >+ >+ >+From 645d30ff371fdf3e16cb1fa69f2e93a848d20bdb 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index f5f091610ac..52297c963e8 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 3aacec00870..98e8a34cd5f 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -403,6 +403,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 >+@@ -470,6 +471,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 1d616e8e9c0dceabebd1f079fc4d652d6bf2060d 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 52297c963e8..99a91528fa8 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 1b7e159c381..61de06659be 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -274,6 +274,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 98e8a34cd5f..3e19ee6c8b9 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -390,6 +390,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 5375e2b99cd5fd9e40d6d5f94eb7d46f366f525e 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) >+ >+[jsutton@samba.org Fixed conflicts] >+--- >+ 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 99a91528fa8..f14439a4ab5 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index da3f69c79c6..14e655313fc 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 61de06659be..294e06027b1 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -289,11 +289,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 >+@@ -309,10 +313,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 >+@@ -332,6 +340,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 3e19ee6c8b9..6c74657e87d 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -411,6 +411,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 >+@@ -479,6 +482,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 >+ >+From 3fdfbd08b9460fb486f100d7091984f41ebd9429 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index f14439a4ab5..50079a1710c 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 294e06027b1..f7c5feda872 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -320,7 +320,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 6c74657e87d..ff287e6cd9d 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -546,8 +546,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 69233dd323b1ce715387e6015542ed234d909295 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 50079a1710c..ecc38538e61 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 6dbed53756f6bac8f63847644b3e9cbb7b6181b0 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 source4/heimdal/kdc/krb5tgs.c source4/heimdal/kdc/krb5tgs.c >+index fb2ef8230c9..cde68b41714 100644 >+--- source4/heimdal/kdc/krb5tgs.c >++++ 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 33d5e5ad3a06ca6a1a62e64d323580ca60f068b8 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 source4/torture/krb5/kdc-canon-heimdal.c source4/torture/krb5/kdc-canon-heimdal.c >+index cd47182c0ef..059078a4ffb 100644 >+--- source4/torture/krb5/kdc-canon-heimdal.c >++++ 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 02ceb9be33dca0e3a885fd7d85b1199f76e04670 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index f7c5feda872..9ff85fe18fc 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -233,21 +233,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 >+@@ -292,11 +286,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 >+@@ -304,15 +293,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 >+@@ -333,16 +318,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 source4/heimdal/kdc/krb5tgs.c source4/heimdal/kdc/krb5tgs.c >+index cde68b41714..6c5c51aa448 100644 >+--- source4/heimdal/kdc/krb5tgs.c >++++ 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 5556f97c782c9be9af47c76f2432bb8480bc0622 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 9ff85fe18fc..bc644587319 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -259,13 +259,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 >+@@ -281,23 +274,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 >+@@ -309,23 +290,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index ff287e6cd9d..c6dc1285837 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -407,8 +407,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 >+@@ -424,8 +422,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 >+@@ -454,8 +450,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 >+@@ -495,8 +489,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 source4/kdc/pac-glue.c source4/kdc/pac-glue.c >+index e0e483662c0..2a96a683cd9 100644 >+--- source4/kdc/pac-glue.c >++++ 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 c62a2b7a218e2c4bdbd476a055049e78b8c0f4ce 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 python/samba/tests/krb5/s4u_tests.py python/samba/tests/krb5/s4u_tests.py >+index 5f37525f393..2953766ef21 100755 >+--- python/samba/tests/krb5/s4u_tests.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index bc644587319..483145f1473 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -243,6 +243,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 46b05cbf803c54cf56dca228fe95a3454027d0cc 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 483145f1473..981d7894158 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -243,7 +243,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 >+@@ -292,6 +291,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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index d017741e30a..bed0ff773f9 100644 >+--- source4/kdc/db-glue.c >++++ 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 93a5264dd68da57e172af50020f670631eeef263 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 981d7894158..94a4509f45a 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -290,5 +290,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 source4/kdc/wdc-samba4.c source4/kdc/wdc-samba4.c >+index ecd182702c3..8c3ce71529c 100644 >+--- source4/kdc/wdc-samba4.c >++++ 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 4cd44326ce38187965c46c71322caedb7a2fbf6c 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index ecc38538e61..2923d53772a 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 94a4509f45a..2de898e73c2 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -278,6 +278,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index c6dc1285837..73e64145e42 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -422,6 +422,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 >+-- >+2.25.1 >+ >+ >+From 925f63f3e464c0fdb91aaa5ed523a6ddb481bfff 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 2de898e73c2..65e4fee9510 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -297,3 +297,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 source4/torture/rpc/remote_pac.c source4/torture/rpc/remote_pac.c >+index c94decef5ce..14c23f674f1 100644 >+--- source4/torture/rpc/remote_pac.c >++++ source4/torture/rpc/remote_pac.c >+@@ -266,7 +266,7 @@ static bool test_PACVerify(struct torture_context *tctx, >+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); >+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed"); >+ >+- num_pac_buffers = 7; >++ num_pac_buffers = 5; >+ if (expect_pac_upn_dns_info) { >+ num_pac_buffers += 1; >+ } >+@@ -323,18 +323,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); >+ >+@@ -1094,7 +1082,7 @@ static bool test_S4U2Proxy(struct torture_context *tctx, >+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); >+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed"); >+ >+- num_pac_buffers = 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"); >+@@ -1134,14 +1122,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 72afa2641c24bd18a32463f0b0de7e91feb54290 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 65e4fee9510..ea08cb44122 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -285,11 +285,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 >+@@ -297,42 +294,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 source4/kdc/wdc-samba4.c source4/kdc/wdc-samba4.c >+index 8c3ce71529c..17af76f4edb 100644 >+--- source4/kdc/wdc-samba4.c >++++ 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 29f15fe2d92831dcf5f4eb6d295df866ff689ee3 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index ea08cb44122..5e94cb63d7a 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -274,16 +274,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 >+@@ -291,6 +281,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 source4/kdc/wdc-samba4.c source4/kdc/wdc-samba4.c >+index 17af76f4edb..713720bcb99 100644 >+--- source4/kdc/wdc-samba4.c >++++ 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 d3436300745c41226d7ed146f269c929133f8f49 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 python/samba/tests/krb5/s4u_tests.py python/samba/tests/krb5/s4u_tests.py >+index 2953766ef21..6ec9af11423 100755 >+--- python/samba/tests/krb5/s4u_tests.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 5e94cb63d7a..2025032a278 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -242,6 +242,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 8f97f78dd8023d88d76fc7de063661d94ebe5400 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 2025032a278..53cc8e6b6a2 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -242,7 +242,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 >+@@ -275,7 +274,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 source4/heimdal/kdc/krb5tgs.c source4/heimdal/kdc/krb5tgs.c >+index 6c5c51aa448..dc356b4daa5 100644 >+--- source4/heimdal/kdc/krb5tgs.c >++++ 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 8585333a8ef54295a60faf47689a8978c0740361 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) >+ >+[jsutton@samba.org Fixed conflicts] >+--- >+ selftest/knownfail_heimdal_kdc | 12 ++++++++++++ >+ source4/selftest/tests.py | 2 +- >+ 2 files changed, 13 insertions(+), 1 deletion(-) >+ >+diff --git selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 53cc8e6b6a2..f71b95f306e 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -241,8 +241,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 >+@@ -274,6 +281,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 >+ >+ >+From 65bb0e3201d60d87a3f228ea161644d9a5f918c5 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index f71b95f306e..53cc8e6b6a2 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -241,15 +241,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 >+@@ -281,11 +274,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 source4/heimdal/kdc/kerberos5.c source4/heimdal/kdc/kerberos5.c >+index 9684364c519..a9e81336615 100644 >+--- source4/heimdal/kdc/kerberos5.c >++++ source4/heimdal/kdc/kerberos5.c >+@@ -1776,7 +1776,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 source4/heimdal/kdc/krb5tgs.c source4/heimdal/kdc/krb5tgs.c >+index dc356b4daa5..38dba8493ae 100644 >+--- source4/heimdal/kdc/krb5tgs.c >++++ 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 source4/heimdal/kdc/windc.c source4/heimdal/kdc/windc.c >+index 93b973f576b..0a5ae5025ec 100644 >+--- source4/heimdal/kdc/windc.c >++++ 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 source4/heimdal/kdc/windc_plugin.h source4/heimdal/kdc/windc_plugin.h >+index c7f2bcb5ed9..d239d0260e7 100644 >+--- source4/heimdal/kdc/windc_plugin.h >++++ 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 source4/kdc/wdc-samba4.c source4/kdc/wdc-samba4.c >+index 713720bcb99..b1d011c09a9 100644 >+--- source4/kdc/wdc-samba4.c >++++ 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 49aafce0a705d47ffd4753ce6c6f452c4f7aa882 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 53cc8e6b6a2..32465cb6042 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -274,9 +274,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 source4/kdc/wdc-samba4.c source4/kdc/wdc-samba4.c >+index b1d011c09a9..d7ce34fb3a9 100644 >+--- source4/kdc/wdc-samba4.c >++++ 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 3fc519edec0159535baa0b659861b73f40632110 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 selftest/knownfail.d/kdc-enterprise selftest/knownfail.d/kdc-enterprise >+deleted file mode 100644 >+index c9b6c98a2ee..00000000000 >+--- 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 32465cb6042..424a8b81c38 100644 >+--- selftest/knownfail_heimdal_kdc >++++ 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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 73e64145e42..4d685af7140 100644 >+--- selftest/knownfail_mit_kdc >++++ 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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index bed0ff773f9..5752ffb821c 100644 >+--- source4/kdc/db-glue.c >++++ 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 787405ef59b70cef011f005a6ed98898c5d43adb 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 python/samba/tests/krb5/compatability_tests.py python/samba/tests/krb5/compatability_tests.py >+index ed2dc565b6d..65e9e3788d5 100755 >+--- python/samba/tests/krb5/compatability_tests.py >++++ 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index 6e96b982167..9506048ee2a 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index 14e655313fc..a2241707d44 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 python/samba/tests/krb5/rodc_tests.py python/samba/tests/krb5/rodc_tests.py >+index 0e252d90262..83ee35d650a 100755 >+--- python/samba/tests/krb5/rodc_tests.py >++++ 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 c0977bee5b8c2f72cb5467e95a6ab034f696eee7 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index 9506048ee2a..58b87eab25b 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 2923d53772a..8cd27dec2aa 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 python/samba/tests/krb5/s4u_tests.py python/samba/tests/krb5/s4u_tests.py >+index 6ec9af11423..49dd89cd764 100755 >+--- python/samba/tests/krb5/s4u_tests.py >++++ 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 c0395578c50fbc4f1946e2f5a065d94f67212eb0 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] >+ >+[jsutton@samba.org Adjusted MIT 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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 4d685af7140..108c6055d0c 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -445,7 +445,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 >+@@ -482,7 +481,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_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_invalid >+-^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 >+@@ -518,7 +516,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 >+@@ -536,21 +533,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 >+ # >+@@ -571,21 +564,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 source4/kdc/mit-kdb/kdb_samba_policies.c source4/kdc/mit-kdb/kdb_samba_policies.c >+index 7bc9a7b3347..3b25fff410b 100644 >+--- source4/kdc/mit-kdb/kdb_samba_policies.c >++++ source4/kdc/mit-kdb/kdb_samba_policies.c >+@@ -159,6 +159,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) >+ { >+@@ -173,6 +174,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) { >+@@ -439,7 +441,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; >+ } >+@@ -490,6 +492,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 source4/kdc/mit_samba.c source4/kdc/mit_samba.c >+index c2a604045d9..df2ba0a906f 100644 >+--- source4/kdc/mit_samba.c >++++ source4/kdc/mit_samba.c >+@@ -407,6 +407,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) >+ { >+@@ -417,9 +418,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); >+@@ -438,12 +442,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); >+@@ -471,8 +479,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); >+ >+@@ -496,6 +504,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; >+@@ -511,8 +520,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"); >+@@ -520,6 +533,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, >+@@ -578,7 +593,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; >+@@ -737,6 +752,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; >+ } >+@@ -766,6 +820,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); >+@@ -831,6 +892,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 >+ */ >+@@ -840,6 +905,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 source4/kdc/mit_samba.h source4/kdc/mit_samba.h >+index 636c77ec97c..4431e82a1b2 100644 >+--- source4/kdc/mit_samba.h >++++ 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 6843c44a45044808f90687f85183e7111a465d1f 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 source4/heimdal/lib/krb5/pac.c source4/heimdal/lib/krb5/pac.c >+index 05bcc523080..100de904662 100644 >+--- source4/heimdal/lib/krb5/pac.c >++++ 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 1b38a28bcaebdae0128518605a422a194747a60f 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 source4/kdc/kpasswd-service-mit.c source4/kdc/kpasswd-service-mit.c >+index 2117c1c1696..b53c1a4618a 100644 >+--- source4/kdc/kpasswd-service-mit.c >++++ 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 f6c5a60336de8fd67a2ef371dd2ee4cf75c53904 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 source4/kdc/kpasswd-service-mit.c source4/kdc/kpasswd-service-mit.c >+index b53c1a4618a..9c4d2801669 100644 >+--- source4/kdc/kpasswd-service-mit.c >++++ 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 6305a55870287191ce4268f6af7fe278ca7f2a30 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index a2241707d44..4120edf93b9 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 8917979641abb03ef858ba72b652178475b6e918 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index 58b87eab25b..2117663b26b 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 python/samba/tests/krb5/kdc_tgs_tests.py python/samba/tests/krb5/kdc_tgs_tests.py >+index 8cd27dec2aa..e52f46152fa 100755 >+--- python/samba/tests/krb5/kdc_tgs_tests.py >++++ 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 245d9a42329a1bfeb3db8431ef105e7758080e14 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index 2117663b26b..685a6f71f88 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index 4120edf93b9..a9a98c36cbf 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 f7fad997cc06a14c9ffd101b26e16598f334148b 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 python/samba/tests/krb5/rfc4120.asn1 python/samba/tests/krb5/rfc4120.asn1 >+index e0831e1f86f..cac884be985 100644 >+--- python/samba/tests/krb5/rfc4120.asn1 >++++ 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 python/samba/tests/krb5/rfc4120_constants.py python/samba/tests/krb5/rfc4120_constants.py >+index a9fdc5735dd..7f0f44500c7 100644 >+--- python/samba/tests/krb5/rfc4120_constants.py >++++ 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 python/samba/tests/krb5/rfc4120_pyasn1.py python/samba/tests/krb5/rfc4120_pyasn1.py >+index 348dd8c63fb..3c02b0efbc1 100644 >+--- python/samba/tests/krb5/rfc4120_pyasn1.py >++++ 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 695c662bdc286d7a4699025f00656f8339ceecd8 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index a9a98c36cbf..df41dff688d 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 ae7dd875cd4362ed4346716db493164c421b889f 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index df41dff688d..421143781ae 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 13fe7e013eccca2c86258084f4443ddb7abaf089 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index 421143781ae..2aed5530455 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 ca582250fcaf2ad3c585f7e31a1a4ce568b7ddb7 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index 685a6f71f88..14f1d1a243d 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 5b030b176b853938b1895ec255e838147d8e7fa9 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index 14f1d1a243d..777b3b4aaf1 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 5c41e20fae268e04aa05e821c7f388ea090727af 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index 777b3b4aaf1..c0ca881985a 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 668825ad56ff70715c626bc3209a6868409e4969 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index 2aed5530455..57010ae73bd 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 450ff39d1c9f538bd828b7b2bee75c88d3dc1ee2 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 python/samba/tests/krb5/kdc_base_test.py python/samba/tests/krb5/kdc_base_test.py >+index c0ca881985a..f0306dde110 100644 >+--- python/samba/tests/krb5/kdc_base_test.py >++++ 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 python/samba/tests/krb5/kpasswd_tests.py python/samba/tests/krb5/kpasswd_tests.py >+new file mode 100755 >+index 00000000000..3a6c7d818dc >+--- /dev/null >++++ 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 python/samba/tests/krb5/raw_testcase.py python/samba/tests/krb5/raw_testcase.py >+index 57010ae73bd..4a78a8eadf3 100644 >+--- python/samba/tests/krb5/raw_testcase.py >++++ 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 python/samba/tests/usage.py python/samba/tests/usage.py >+index 6bbd96e7a08..a1210ada579 100644 >+--- python/samba/tests/usage.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 424a8b81c38..54e69a48bc1 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -271,3 +271,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 108c6055d0c..53638afc17a 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -575,3 +575,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 >+-- >+2.25.1 >+ >+ >+From 29ec8b2369b5f5e2a660a3165d2528982514a0f2 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 54e69a48bc1..40e24f3155b 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -276,24 +276,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 53638afc17a..a914c4d3492 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -578,26 +578,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 source4/kdc/kpasswd-helper.c source4/kdc/kpasswd-helper.c >+index 995f54825b5..55a2f5b3bf6 100644 >+--- source4/kdc/kpasswd-helper.c >++++ 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 3a8da51396f3bf9d4caf8dbd4e75a0314aa47046 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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index a914c4d3492..f64291e776d 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -579,7 +579,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 source4/kdc/kpasswd-service.c source4/kdc/kpasswd-service.c >+index 8f1679e4a28..a3c57a67dd1 100644 >+--- source4/kdc/kpasswd-service.c >++++ source4/kdc/kpasswd-service.c >+@@ -253,6 +253,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; >+ } >+@@ -262,6 +263,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 cf9e37604409ba0c3c5904af40beb2975c309ad4 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 lib/krb5_wrap/krb5_samba.c lib/krb5_wrap/krb5_samba.c >+index 76c2dcd2126..610efcc9b87 100644 >+--- lib/krb5_wrap/krb5_samba.c >++++ 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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index f64291e776d..633bf79e8e0 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -579,9 +579,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 cf749fac346ef59c91a9ea87f5e7ddec2e5649c7 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 40e24f3155b..3b494baa658 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -276,9 +276,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 633bf79e8e0..f64291e776d 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -579,13 +579,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 source4/kdc/kpasswd-service.c source4/kdc/kpasswd-service.c >+index a3c57a67dd1..b4706de1ad7 100644 >+--- source4/kdc/kpasswd-service.c >++++ source4/kdc/kpasswd-service.c >+@@ -312,7 +312,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 198256e2184897300e1cea4343437c3b7b6f74ad 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 source4/auth/gensec/gensec_krb5.c source4/auth/gensec/gensec_krb5.c >+index 7d87b3ac6b9..104e4639c44 100644 >+--- source4/auth/gensec/gensec_krb5.c >++++ 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 source4/auth/gensec/gensec_krb5_helpers.c source4/auth/gensec/gensec_krb5_helpers.c >+new file mode 100644 >+index 00000000000..21f2f1e884e >+--- /dev/null >++++ 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 source4/auth/gensec/gensec_krb5_helpers.h source4/auth/gensec/gensec_krb5_helpers.h >+new file mode 100644 >+index 00000000000..d7b694dad0c >+--- /dev/null >++++ 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 source4/auth/gensec/gensec_krb5_internal.h source4/auth/gensec/gensec_krb5_internal.h >+new file mode 100644 >+index 00000000000..0bb796f1b2a >+--- /dev/null >++++ 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 source4/auth/gensec/wscript_build source4/auth/gensec/wscript_build >+index d14a50ff273..20271f1665b 100644 >+--- source4/auth/gensec/wscript_build >++++ 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 6c4fd575d706b2695090941ad7947b30abdb9071 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 3b494baa658..5cd8615f6a9 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -277,7 +277,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index f64291e776d..46b0f1fa9ed 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -580,7 +580,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 source4/kdc/kpasswd-service-heimdal.c source4/kdc/kpasswd-service-heimdal.c >+index c804852c3a7..1a6c2b60d03 100644 >+--- source4/kdc/kpasswd-service-heimdal.c >++++ 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 source4/kdc/kpasswd-service-mit.c source4/kdc/kpasswd-service-mit.c >+index 9c4d2801669..de4c6f3f622 100644 >+--- source4/kdc/kpasswd-service-mit.c >++++ 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 source4/kdc/wscript_build source4/kdc/wscript_build >+index 0edca94e75f..13ba3947cf6 100644 >+--- source4/kdc/wscript_build >++++ 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 69e742e6208bd471eb509795bd753a0c98392bf6 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 source4/kdc/kpasswd-service-heimdal.c source4/kdc/kpasswd-service-heimdal.c >+index 1a6c2b60d03..a0352d1ad35 100644 >+--- source4/kdc/kpasswd-service-heimdal.c >++++ 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 b5adf7cc6d740c8f4f7b5888f106de24a1181da7 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> >+ >+[jsutton@samba.org Fixed conflict and renamed --use-krb5-ccache to >+ --krb5-ccache] >+--- >+ testprogs/blackbox/test_kpasswd_heimdal.sh | 4 ++-- >+ 1 file changed, 2 insertions(+), 2 deletions(-) >+ >+diff --git testprogs/blackbox/test_kpasswd_heimdal.sh testprogs/blackbox/test_kpasswd_heimdal.sh >+index 7351ce022d1..1e895daa162 100755 >+--- testprogs/blackbox/test_kpasswd_heimdal.sh >++++ testprogs/blackbox/test_kpasswd_heimdal.sh >+@@ -72,7 +72,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" -k yes || failed=`expr $failed + 1` >++ "ls" "$SMB_UNC" --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 -k no --newpassword=$TEST_PASSWORD_NEW || failed=`expr $failed + 1` >+@@ -85,7 +85,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" -k yes || failed=`expr $failed + 1` >++ "ls" "$SMB_UNC" --krb5-ccache=${KRB5CCNAME} || failed=`expr $failed + 1` >+ >+ ########################################################### >+ ### check that a short password is rejected >+-- >+2.25.1 >+ >+ >+From 91a1b0955a053f73e6d531f0f12eaa604aca79d7 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 selftest/knownfail.d/kadmin_changepw selftest/knownfail.d/kadmin_changepw >+new file mode 100644 >+index 00000000000..97c14793ea5 >+--- /dev/null >++++ selftest/knownfail.d/kadmin_changepw >+@@ -0,0 +1 @@ >++^samba4.blackbox.kpasswd.MIT kpasswd.change.user.password >+diff --git testprogs/blackbox/test_kpasswd_heimdal.sh testprogs/blackbox/test_kpasswd_heimdal.sh >+index 1e895daa162..059b7a8e4d1 100755 >+--- testprogs/blackbox/test_kpasswd_heimdal.sh >++++ 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" >+@@ -142,6 +144,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 36d94ffb9c99f3e515024424020e3e03e98f34f5 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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index 5752ffb821c..45159e6e64d 100644 >+--- source4/kdc/db-glue.c >++++ 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 f68877af829bf73da8e965c9458a9846d1757038 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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index 45159e6e64d..ac0c206b5c1 100644 >+--- source4/kdc/db-glue.c >++++ 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 fa4742e1b9dea0b9c379f00666478bd41c021634 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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index ac0c206b5c1..385c118a073 100644 >+--- source4/kdc/db-glue.c >++++ 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 3cab62893668742781551dae6505558e47cf08b5 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 selftest/knownfail.d/kadmin_changepw selftest/knownfail.d/kadmin_changepw >+deleted file mode 100644 >+index 97c14793ea5..00000000000 >+--- selftest/knownfail.d/kadmin_changepw >++++ /dev/null >+@@ -1 +0,0 @@ >+-^samba4.blackbox.kpasswd.MIT kpasswd.change.user.password >+diff --git selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 5cd8615f6a9..49ab29f115d 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -274,8 +274,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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index 385c118a073..d2d7136608e 100644 >+--- source4/kdc/db-glue.c >++++ 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 531e7b596d35785bee61f3b4289e38ece1530f94 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] >+ >+[jsutton@samba.org Fixed conflicts] >+--- >+ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 49ab29f115d..387ccea3ba7 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -275,7 +275,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 46b0f1fa9ed..c2a31b4a140 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -580,7 +580,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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index d2d7136608e..073ec83c8cf 100644 >+--- source4/kdc/db-glue.c >++++ 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 source4/kdc/mit-kdb/kdb_samba_principals.c source4/kdc/mit-kdb/kdb_samba_principals.c >+index cc67c2392be..2059ffa855e 100644 >+--- source4/kdc/mit-kdb/kdb_samba_principals.c >++++ source4/kdc/mit-kdb/kdb_samba_principals.c >+@@ -27,11 +27,11 @@ >+ #include <profile.h> >+ #include <kdb.h> >+ >++#include "kdc/samba_kdc.h" >+ #include "kdc/mit_samba.h" >+ #include "kdb_samba.h" >+ >+ #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 source4/kdc/samba_kdc.h source4/kdc/samba_kdc.h >+index e228a82ce6a..8010d7c35ed 100644 >+--- source4/kdc/samba_kdc.h >++++ 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 abdac4241dd08dd90a08db877edd799f3833c2b4 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 387ccea3ba7..afb9bcf1209 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -275,7 +275,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 source4/heimdal/kdc/krb5tgs.c source4/heimdal/kdc/krb5tgs.c >+index 38dba8493ae..15be136496f 100644 >+--- source4/heimdal/kdc/krb5tgs.c >++++ 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 389851bcf399f9511e2cb797350c37ce91aa5849 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 python/samba/tests/krb5/as_req_tests.py python/samba/tests/krb5/as_req_tests.py >+index 315720f85d6..054a49b64aa 100755 >+--- python/samba/tests/krb5/as_req_tests.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index afb9bcf1209..dbfff5784e6 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -278,3 +278,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index c2a31b4a140..0f90ea10299 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -583,3 +583,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 d40593be83144713cfc43e4eb1c7bc2d925a0da0 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index dbfff5784e6..afb9bcf1209 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -278,7 +278,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 0f90ea10299..c2a31b4a140 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -583,7 +583,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 source4/kdc/db-glue.c source4/kdc/db-glue.c >+index 073ec83c8cf..cfa2097acbd 100644 >+--- source4/kdc/db-glue.c >++++ 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 42ba919c06c24c42ef123304de0c2ca8c689591a 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 source4/kdc/kdc-heimdal.c source4/kdc/kdc-heimdal.c >+index ba74df4f2ec..a4c845b62f8 100644 >+--- source4/kdc/kdc-heimdal.c >++++ 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 source4/kdc/kdc-server.h source4/kdc/kdc-server.h >+index fd883c2e4b4..89b30f122f5 100644 >+--- source4/kdc/kdc-server.h >++++ 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 source4/kdc/kdc-service-mit.c source4/kdc/kdc-service-mit.c >+index 5d4180aa7cc..22663b6ecc8 100644 >+--- source4/kdc/kdc-service-mit.c >++++ 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 source4/kdc/kpasswd-service.c source4/kdc/kpasswd-service.c >+index b4706de1ad7..0d2acd8d9e8 100644 >+--- source4/kdc/kpasswd-service.c >++++ source4/kdc/kpasswd-service.c >+@@ -167,7 +167,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 997f50c66471071efb8e02d8efbe4bf5d932e7ee 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 source4/kdc/hdb-samba4-plugin.c source4/kdc/hdb-samba4-plugin.c >+index 6f76124995d..4b90a766f76 100644 >+--- source4/kdc/hdb-samba4-plugin.c >++++ 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 c0c4b7a4bd229bd36d586faec6249baaba8e7adc 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index afb9bcf1209..0d93253f999 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -275,6 +275,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 source4/kdc/hdb-samba4-plugin.c source4/kdc/hdb-samba4-plugin.c >+index 4b90a766f76..dba25e825de 100644 >+--- source4/kdc/hdb-samba4-plugin.c >++++ 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 source4/kdc/hdb-samba4.c source4/kdc/hdb-samba4.c >+index 43e836f8360..a8aae50b5b0 100644 >+--- source4/kdc/hdb-samba4.c >++++ 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 source4/kdc/kdc-glue.h source4/kdc/kdc-glue.h >+index c083b8c6429..ff8684e1666 100644 >+--- source4/kdc/kdc-glue.h >++++ 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 340181bc1100fa31c63af88214a3d8328b944fe9 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 0d93253f999..424a8b81c38 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -271,7 +271,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index c2a31b4a140..0d2f5bab6d2 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -581,5 +581,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 source4/kdc/kpasswd-service.c source4/kdc/kpasswd-service.c >+index 0d2acd8d9e8..b6400be0c49 100644 >+--- source4/kdc/kpasswd-service.c >++++ 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 >+@@ -158,6 +159,20 @@ kdc_code kpasswd_process(struct kdc_server *kdc, >+ >+ cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx); >+ >++ /* >++ * 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); >+@@ -165,6 +180,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 95afbc2da9b541fb8f2eebdcd411f5873d1675ac 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 python/samba/tests/krb5/kpasswd_tests.py python/samba/tests/krb5/kpasswd_tests.py >+index 3a6c7d818dc..0db857f7bbd 100755 >+--- python/samba/tests/krb5/kpasswd_tests.py >++++ 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 424a8b81c38..42beccaed58 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -271,3 +271,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 0d2f5bab6d2..9fc34e5d8db 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -581,3 +581,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 4b61092459b403b2945daa9082052366f3508b69 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 auth/auth_sam_reply.c auth/auth_sam_reply.c >+index b5b6362dc93..2e27e5715d1 100644 >+--- auth/auth_sam_reply.c >++++ 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 auth/auth_util.c auth/auth_util.c >+index fe01babd107..ec9094d0f15 100644 >+--- auth/auth_util.c >++++ 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 librpc/idl/auth.idl librpc/idl/auth.idl >+index 1092935b971..f7658cdde28 100644 >+--- librpc/idl/auth.idl >++++ 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 source4/auth/ntlm/auth_developer.c source4/auth/ntlm/auth_developer.c >+index 1823989c68d..6e92252d5c5 100644 >+--- source4/auth/ntlm/auth_developer.c >++++ 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 source4/auth/sam.c source4/auth/sam.c >+index 8b233bab3ad..7c609655fcb 100644 >+--- source4/auth/sam.c >++++ 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 source4/auth/session.c source4/auth/session.c >+index 8e44dcd24f1..d6e936dd1f1 100644 >+--- source4/auth/session.c >++++ 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 source4/auth/system_session.c source4/auth/system_session.c >+index 85b8f1c4edb..2518d654e8b 100644 >+--- source4/auth/system_session.c >++++ source4/auth/system_session.c >+@@ -115,7 +115,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 >+@@ -191,7 +191,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; >+@@ -356,7 +356,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 89c6e36938c27b572573b06d1b35db210bfda99b 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 source4/auth/kerberos/kerberos_pac.c source4/auth/kerberos/kerberos_pac.c >+index 54ef4d61b02..bd0ae20e007 100644 >+--- source4/auth/kerberos/kerberos_pac.c >++++ 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 d5af460403d3949ba266f5c74f051247cd7ce752 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 selftest/knownfail_heimdal_kdc selftest/knownfail_heimdal_kdc >+index 42beccaed58..424a8b81c38 100644 >+--- selftest/knownfail_heimdal_kdc >++++ selftest/knownfail_heimdal_kdc >+@@ -271,7 +271,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 selftest/knownfail_mit_kdc selftest/knownfail_mit_kdc >+index 9fc34e5d8db..0d2f5bab6d2 100644 >+--- selftest/knownfail_mit_kdc >++++ selftest/knownfail_mit_kdc >+@@ -581,7 +581,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 source4/kdc/kpasswd-helper.c source4/kdc/kpasswd-helper.c >+index 55a2f5b3bf6..2ffdb79aea5 100644 >+--- source4/kdc/kpasswd-helper.c >++++ 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 source4/kdc/kpasswd-helper.h source4/kdc/kpasswd-helper.h >+index 8fad81e0a5d..94a6e2acfdd 100644 >+--- source4/kdc/kpasswd-helper.h >++++ 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 source4/kdc/kpasswd-service-heimdal.c source4/kdc/kpasswd-service-heimdal.c >+index a0352d1ad35..4d009b9eb24 100644 >+--- source4/kdc/kpasswd-service-heimdal.c >++++ 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 source4/kdc/kpasswd-service-mit.c source4/kdc/kpasswd-service-mit.c >+index de4c6f3f622..6b051567b6e 100644 >+--- source4/kdc/kpasswd-service-mit.c >++++ 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 a6231af1f1c03cd81614332f867916e1748e03a8 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> >+ >+[jsutton@samba.org Changed --use-krb5-ccache to -k yes to match >+ surrounding usage] >+--- >+ testprogs/blackbox/test_kinit_trusts_heimdal.sh | 6 +++++- >+ 1 file changed, 5 insertions(+), 1 deletion(-) >+ >+diff --git testprogs/blackbox/test_kinit_trusts_heimdal.sh testprogs/blackbox/test_kinit_trusts_heimdal.sh >+index bf0b81a0473..621434eac35 100755 >+--- testprogs/blackbox/test_kinit_trusts_heimdal.sh >++++ testprogs/blackbox/test_kinit_trusts_heimdal.sh >+@@ -54,6 +54,10 @@ testit "kinit with password" $samba4kinit $enctype --password-file=$PREFIX/tmppa >+ test_smbclient "Test login with user kerberos ccache" 'ls' "$unc" -k yes || 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" -k yes || 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` >+@@ -94,5 +98,5 @@ testit "wbinfo check outgoing trust pw" $VALGRIND $wbinfo --check-secret --domai >+ >+ test_smbclient "Test user login with the changed outgoing secret" 'ls' "$unc" -k yes -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 >+ >+ >+From f6e1750c4fc966c29c2e0663d3c04e87057fa0c3 Mon Sep 17 00:00:00 2001 >+From: Jeremy Allison <jra@samba.org> >+Date: Tue, 7 Jun 2022 09:40:45 -0700 >+Subject: [PATCH 98/99] CVE-2022-32742: s4: torture: Add raw.write.bad-write >+ test. >+ >+Reproduces the test code in: >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15085 >+ >+Add knownfail. >+ >+Signed-off-by: Jeremy Allison <jra@samba.org> >+Reviewed-by: David Disseldorp <ddiss@samba.org> >+--- >+ selftest/knownfail.d/bad-write | 2 + >+ source4/torture/raw/write.c | 89 ++++++++++++++++++++++++++++++++++ >+ 2 files changed, 91 insertions(+) >+ create mode 100644 selftest/knownfail.d/bad-write >+ >+diff --git selftest/knownfail.d/bad-write selftest/knownfail.d/bad-write >+new file mode 100644 >+index 00000000000..5fc16606a13 >+--- /dev/null >++++ selftest/knownfail.d/bad-write >+@@ -0,0 +1,2 @@ >++^samba3.raw.write.bad-write\(nt4_dc_smb1\) >++^samba3.raw.write.bad-write\(ad_dc_smb1\) >+diff --git source4/torture/raw/write.c source4/torture/raw/write.c >+index 0a2f50f425b..661485bb548 100644 >+--- source4/torture/raw/write.c >++++ source4/torture/raw/write.c >+@@ -25,6 +25,7 @@ >+ #include "libcli/libcli.h" >+ #include "torture/util.h" >+ #include "torture/raw/proto.h" >++#include "libcli/raw/raw_proto.h" >+ >+ #define CHECK_STATUS(status, correct) do { \ >+ if (!NT_STATUS_EQUAL(status, correct)) { \ >+@@ -694,6 +695,93 @@ done: >+ return ret; >+ } >+ >++/* >++ test a deliberately bad SMB1 write. >++*/ >++static bool test_bad_write(struct torture_context *tctx, >++ struct smbcli_state *cli) >++{ >++ bool ret = false; >++ int fnum = -1; >++ struct smbcli_request *req = NULL; >++ const char *fname = BASEDIR "\\badwrite.txt"; >++ bool ok = false; >++ >++ if (!torture_setup_dir(cli, BASEDIR)) { >++ torture_fail(tctx, "failed to setup basedir"); >++ } >++ >++ torture_comment(tctx, "Testing RAW_BAD_WRITE\n"); >++ >++ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); >++ if (fnum == -1) { >++ torture_fail_goto(tctx, >++ done, >++ talloc_asprintf(tctx, >++ "Failed to create %s - %s\n", >++ fname, >++ smbcli_errstr(cli->tree))); >++ } >++ >++ req = smbcli_request_setup(cli->tree, >++ SMBwrite, >++ 5, >++ 0); >++ if (req == NULL) { >++ torture_fail_goto(tctx, >++ done, >++ talloc_asprintf(tctx, "talloc fail\n")); >++ } >++ >++ SSVAL(req->out.vwv, VWV(0), fnum); >++ SSVAL(req->out.vwv, VWV(1), 65535); /* bad write length. */ >++ SIVAL(req->out.vwv, VWV(2), 0); /* offset */ >++ SSVAL(req->out.vwv, VWV(4), 0); /* remaining. */ >++ >++ if (!smbcli_request_send(req)) { >++ torture_fail_goto(tctx, >++ done, >++ talloc_asprintf(tctx, "Send failed\n")); >++ } >++ >++ if (!smbcli_request_receive(req)) { >++ torture_fail_goto(tctx, >++ done, >++ talloc_asprintf(tctx, "Reveive failed\n")); >++ } >++ >++ /* >++ * Check for expected error codes. >++ * ntvfs returns NT_STATUS_UNSUCCESSFUL. >++ */ >++ ok = (NT_STATUS_EQUAL(req->status, NT_STATUS_INVALID_PARAMETER) || >++ NT_STATUS_EQUAL(req->status, NT_STATUS_UNSUCCESSFUL)); >++ >++ if (!ok) { >++ torture_fail_goto(tctx, >++ done, >++ talloc_asprintf(tctx, >++ "Should have returned " >++ "NT_STATUS_INVALID_PARAMETER or " >++ "NT_STATUS_UNSUCCESSFUL " >++ "got %s\n", >++ nt_errstr(req->status))); >++ } >++ >++ ret = true; >++ >++done: >++ if (req != NULL) { >++ smbcli_request_destroy(req); >++ } >++ if (fnum != -1) { >++ smbcli_close(cli->tree, fnum); >++ } >++ smb_raw_exit(cli->session); >++ smbcli_deltree(cli->tree, BASEDIR); >++ return ret; >++} >++ >+ /* >+ basic testing of write calls >+ */ >+@@ -705,6 +793,7 @@ struct torture_suite *torture_raw_write(TALLOC_CTX *mem_ctx) >+ torture_suite_add_1smb_test(suite, "write unlock", test_writeunlock); >+ torture_suite_add_1smb_test(suite, "write close", test_writeclose); >+ torture_suite_add_1smb_test(suite, "writex", test_writex); >++ torture_suite_add_1smb_test(suite, "bad-write", test_bad_write); >+ >+ return suite; >+ } >+-- >+2.25.1 >+ >+ >+From 7720e0acfd7ea6a2339f3e389aa8dcedd6174095 Mon Sep 17 00:00:00 2001 >+From: Jeremy Allison <jra@samba.org> >+Date: Wed, 8 Jun 2022 13:50:51 -0700 >+Subject: [PATCH 99/99] CVE-2022-32742: s3: smbd: Harden the smbreq_bufrem() >+ macro. >+ >+Fixes the raw.write.bad-write test. >+ >+NB. We need the two (==0) changes in source3/smbd/reply.c >+as the gcc optimizer now knows that the return from >+smbreq_bufrem() can never be less than zero. >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15085 >+ >+Remove knownfail. >+ >+Signed-off-by: Jeremy Allison <jra@samba.org> >+Reviewed-by: David Disseldorp <ddiss@samba.org> >+--- >+ selftest/knownfail.d/bad-write | 2 -- >+ source3/include/smb_macros.h | 2 +- >+ source3/smbd/reply.c | 4 ++-- >+ 3 files changed, 3 insertions(+), 5 deletions(-) >+ delete mode 100644 selftest/knownfail.d/bad-write >+ >+diff --git selftest/knownfail.d/bad-write selftest/knownfail.d/bad-write >+deleted file mode 100644 >+index 5fc16606a13..00000000000 >+--- selftest/knownfail.d/bad-write >++++ /dev/null >+@@ -1,2 +0,0 @@ >+-^samba3.raw.write.bad-write\(nt4_dc_smb1\) >+-^samba3.raw.write.bad-write\(ad_dc_smb1\) >+diff --git source3/include/smb_macros.h source3/include/smb_macros.h >+index def122727f0..de1322a503b 100644 >+--- source3/include/smb_macros.h >++++ source3/include/smb_macros.h >+@@ -152,7 +152,7 @@ >+ >+ /* the remaining number of bytes in smb buffer 'buf' from pointer 'p'. */ >+ #define smb_bufrem(buf, p) (smb_buflen(buf)-PTR_DIFF(p, smb_buf(buf))) >+-#define smbreq_bufrem(req, p) (req->buflen - PTR_DIFF(p, req->buf)) >++#define smbreq_bufrem(req, p) ((req)->buflen < PTR_DIFF((p), (req)->buf) ? 0 : (req)->buflen - PTR_DIFF((p), (req)->buf)) >+ >+ >+ /* Note that chain_size must be available as an extern int to this macro. */ >+diff --git source3/smbd/reply.c source3/smbd/reply.c >+index f33326564f7..b5abe588910 100644 >+--- source3/smbd/reply.c >++++ source3/smbd/reply.c >+@@ -342,7 +342,7 @@ size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req, >+ { >+ ssize_t bufrem = smbreq_bufrem(req, src); >+ >+- if (bufrem < 0) { >++ if (bufrem == 0) { >+ *err = NT_STATUS_INVALID_PARAMETER; >+ return 0; >+ } >+@@ -380,7 +380,7 @@ size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req, >+ { >+ ssize_t bufrem = smbreq_bufrem(req, src); >+ >+- if (bufrem < 0) { >++ if (bufrem == 0) { >+ return 0; >+ } >+ >+-- >+2.25.1 >+ >diff --git a/net/samba413/files/patch-waf-2.0.20 b/net/samba413/files/patch-waf-2.0.20 >new file mode 100644 >index 000000000000..3c40ea15f0ed >--- /dev/null >+++ b/net/samba413/files/patch-waf-2.0.20 >@@ -0,0 +1,1663 @@ >+From 5fc3a71d0f54b176d3cb2e399718d0468507e797 Mon Sep 17 00:00:00 2001 >+From: David Mulder <dmulder@suse.com> >+Date: Mon, 24 Aug 2020 13:12:46 -0600 >+Subject: [PATCH] waf: upgrade to 2.0.20 >+ >+This contain an important change: >+"Fix gccdeps.scan() returning nodes that no longer exist on disk." >+https://gitlab.com/ita1024/waf/-/merge_requests/2293 >+ >+Signed-off-by: David Mulder <dmulder@suse.com> >+Reviewed-by: Stefan Metzmacher <metze@samba.org> >+--- >+ buildtools/bin/waf | 2 +- >+ buildtools/wafsamba/samba_utils.py | 2 +- >+ buildtools/wafsamba/samba_waf18.py | 3 +- >+ buildtools/wafsamba/wafsamba.py | 2 +- >+ third_party/waf/waflib/Configure.py | 25 +- >+ third_party/waf/waflib/Context.py | 18 +- >+ third_party/waf/waflib/Options.py | 31 +- >+ third_party/waf/waflib/Scripting.py | 6 +- >+ third_party/waf/waflib/Tools/c_aliases.py | 4 +- >+ third_party/waf/waflib/Tools/c_config.py | 22 +- >+ third_party/waf/waflib/Tools/c_tests.py | 15 +- >+ third_party/waf/waflib/Tools/compiler_c.py | 2 +- >+ third_party/waf/waflib/Tools/compiler_cxx.py | 2 +- >+ third_party/waf/waflib/Tools/fc.py | 4 +- >+ third_party/waf/waflib/Tools/irixcc.py | 14 +- >+ third_party/waf/waflib/Tools/javaw.py | 2 +- >+ third_party/waf/waflib/Tools/python.py | 2 +- >+ third_party/waf/waflib/Tools/qt5.py | 6 +- >+ third_party/waf/waflib/Utils.py | 2 +- >+ .../extras/clang_compilation_database.py | 172 ++++-- >+ third_party/waf/waflib/extras/doxygen.py | 1 + >+ third_party/waf/waflib/extras/gccdeps.py | 15 +- >+ third_party/waf/waflib/extras/javatest.py | 135 ++++- >+ third_party/waf/waflib/extras/msvc_pdb.py | 46 ++ >+ third_party/waf/waflib/extras/pytest.py | 17 +- >+ third_party/waf/waflib/extras/wafcache.py | 524 ++++++++++++++++++ >+ 26 files changed, 942 insertions(+), 132 deletions(-) >+ create mode 100644 third_party/waf/waflib/extras/msvc_pdb.py >+ create mode 100644 third_party/waf/waflib/extras/wafcache.py >+ >+diff --git buildtools/bin/waf buildtools/bin/waf >+index 11ce8e7480a..feabe25d131 100755 >+--- buildtools/bin/waf >++++ buildtools/bin/waf >+@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. >+ >+ import os, sys, inspect >+ >+-VERSION="2.0.18" >++VERSION="2.0.20" >+ REVISION="x" >+ GIT="x" >+ INSTALL="x" >+diff --git buildtools/wafsamba/samba_utils.py buildtools/wafsamba/samba_utils.py >+index 4afee249d33..0587f525aff 100644 >+--- buildtools/wafsamba/samba_utils.py >++++ buildtools/wafsamba/samba_utils.py >+@@ -459,7 +459,7 @@ def RECURSE(ctx, directory): >+ return >+ visited_dirs.add(key) >+ relpath = os.path.relpath(abspath, ctx.path.abspath()) >+- if ctxclass in ['tmp', 'OptionsContext', 'ConfigurationContext', 'BuildContext']: >++ if ctxclass in ['tmp', 'OptionsContext', 'ConfigurationContext', 'BuildContext', 'ClangDbContext']: >+ return ctx.recurse(relpath) >+ if 'waflib.extras.compat15' in sys.modules: >+ return ctx.recurse(relpath) >+diff --git buildtools/wafsamba/samba_waf18.py buildtools/wafsamba/samba_waf18.py >+index c0bb6bfcf55..ecf3891f175 100644 >+--- buildtools/wafsamba/samba_waf18.py >++++ buildtools/wafsamba/samba_waf18.py >+@@ -5,6 +5,7 @@ from waflib import Build, Configure, Node, Utils, Options, Logs, TaskGen >+ from waflib import ConfigSet >+ from waflib.TaskGen import feature, after >+ from waflib.Configure import conf, ConfigurationContext >++from waflib.extras import clang_compilation_database >+ >+ from waflib.Tools.flex import decide_ext >+ >+@@ -37,7 +38,7 @@ TaskGen.declare_chain( >+ ) >+ >+ >+-for y in (Build.BuildContext, Build.CleanContext, Build.InstallContext, Build.UninstallContext, Build.ListContext): >++for y in (Build.BuildContext, Build.CleanContext, Build.InstallContext, Build.UninstallContext, Build.ListContext, clang_compilation_database.ClangDbContext): >+ class tmp(y): >+ variant = 'default' >+ >+diff --git buildtools/wafsamba/wafsamba.py buildtools/wafsamba/wafsamba.py >+index 7827d374654..9f6ee4f5c7f 100644 >+--- buildtools/wafsamba/wafsamba.py >++++ buildtools/wafsamba/wafsamba.py >+@@ -38,7 +38,7 @@ LIB_PATH="shared" >+ >+ os.environ['PYTHONUNBUFFERED'] = '1' >+ >+-if Context.HEXVERSION not in (0x2001200,): >++if Context.HEXVERSION not in (0x2001400,): >+ Logs.error(''' >+ Please use the version of waf that comes with Samba, not >+ a system installed version. See http://wiki.samba.org/index.php/Waf >+diff --git third_party/waf/waflib/Configure.py third_party/waf/waflib/Configure.py >+index 5762eb66954..e7333948489 100644 >+--- third_party/waf/waflib/Configure.py >++++ third_party/waf/waflib/Configure.py >+@@ -508,23 +508,27 @@ def find_binary(self, filenames, exts, paths): >+ @conf >+ def run_build(self, *k, **kw): >+ """ >+- Create a temporary build context to execute a build. A reference to that build >+- context is kept on self.test_bld for debugging purposes, and you should not rely >+- on it too much (read the note on the cache below). >+- The parameters given in the arguments to this function are passed as arguments for >+- a single task generator created in the build. Only three parameters are obligatory: >++ Create a temporary build context to execute a build. A temporary reference to that build >++ context is kept on self.test_bld for debugging purposes. >++ The arguments to this function are passed to a single task generator for that build. >++ Only three parameters are mandatory: >+ >+ :param features: features to pass to a task generator created in the build >+ :type features: list of string >+ :param compile_filename: file to create for the compilation (default: *test.c*) >+ :type compile_filename: string >+- :param code: code to write in the filename to compile >++ :param code: input file contents >+ :type code: string >+ >+- Though this function returns *0* by default, the build may set an attribute named *retval* on the >++ Though this function returns *0* by default, the build may bind attribute named *retval* on the >+ build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example. >+ >+- This function also features a cache which can be enabled by the following option:: >++ The temporary builds creates a temporary folder; the name of that folder is calculated >++ by hashing input arguments to this function, with the exception of :py:class:`waflib.ConfigSet.ConfigSet` >++ objects which are used for both reading and writing values. >++ >++ This function also features a cache which is disabled by default; that cache relies >++ on the hash value calculated as indicated above:: >+ >+ def options(opt): >+ opt.add_option('--confcache', dest='confcache', default=0, >+@@ -538,7 +542,10 @@ def run_build(self, *k, **kw): >+ buf = [] >+ for key in sorted(kw.keys()): >+ v = kw[key] >+- if hasattr(v, '__call__'): >++ if isinstance(v, ConfigSet.ConfigSet): >++ # values are being written to, so they are excluded from contributing to the hash >++ continue >++ elif hasattr(v, '__call__'): >+ buf.append(Utils.h_fun(v)) >+ else: >+ buf.append(str(v)) >+diff --git third_party/waf/waflib/Context.py third_party/waf/waflib/Context.py >+index e3305fa3341..3f1b4fa48ab 100644 >+--- third_party/waf/waflib/Context.py >++++ third_party/waf/waflib/Context.py >+@@ -6,20 +6,30 @@ >+ Classes and functions enabling the command system >+ """ >+ >+-import os, re, imp, sys >++import os, re, sys >+ from waflib import Utils, Errors, Logs >+ import waflib.Node >+ >++if sys.hexversion > 0x3040000: >++ import types >++ class imp(object): >++ new_module = lambda x: types.ModuleType(x) >++else: >++ import imp >++ >+ # the following 3 constants are updated on each new release (do not touch) >+-HEXVERSION=0x2001200 >++HEXVERSION=0x2001400 >+ """Constant updated on new releases""" >+ >+-WAFVERSION="2.0.18" >++WAFVERSION="2.0.20" >+ """Constant updated on new releases""" >+ >+-WAFREVISION="314689b8994259a84f0de0aaef74d7ce91f541ad" >++WAFREVISION="668769470956da8c5b60817cb8884cd7d0f87cd4" >+ """Git revision when the waf version is updated""" >+ >++WAFNAME="waf" >++"""Application name displayed on --help""" >++ >+ ABI = 20 >+ """Version of the build data cache file format (used in :py:const:`waflib.Context.DBFILE`)""" >+ >+diff --git third_party/waf/waflib/Options.py third_party/waf/waflib/Options.py >+index ad802d4b905..d4104917c82 100644 >+--- third_party/waf/waflib/Options.py >++++ third_party/waf/waflib/Options.py >+@@ -44,7 +44,7 @@ class opt_parser(optparse.OptionParser): >+ """ >+ def __init__(self, ctx, allow_unknown=False): >+ optparse.OptionParser.__init__(self, conflict_handler='resolve', add_help_option=False, >+- version='waf %s (%s)' % (Context.WAFVERSION, Context.WAFREVISION)) >++ version='%s %s (%s)' % (Context.WAFNAME, Context.WAFVERSION, Context.WAFREVISION)) >+ self.formatter.width = Logs.get_term_cols() >+ self.ctx = ctx >+ self.allow_unknown = allow_unknown >+@@ -62,6 +62,21 @@ class opt_parser(optparse.OptionParser): >+ else: >+ self.error(str(e)) >+ >++ def _process_long_opt(self, rargs, values): >++ # --custom-option=-ftxyz is interpreted as -f -t... see #2280 >++ if self.allow_unknown: >++ back = [] + rargs >++ try: >++ optparse.OptionParser._process_long_opt(self, rargs, values) >++ except optparse.BadOptionError: >++ while rargs: >++ rargs.pop() >++ rargs.extend(back) >++ rargs.pop(0) >++ raise >++ else: >++ optparse.OptionParser._process_long_opt(self, rargs, values) >++ >+ def print_usage(self, file=None): >+ return self.print_help(file) >+ >+@@ -96,11 +111,11 @@ class opt_parser(optparse.OptionParser): >+ lst.sort() >+ ret = '\n'.join(lst) >+ >+- return '''waf [commands] [options] >++ return '''%s [commands] [options] >+ >+-Main commands (example: ./waf build -j4) >++Main commands (example: ./%s build -j4) >+ %s >+-''' % ret >++''' % (Context.WAFNAME, Context.WAFNAME, ret) >+ >+ >+ class OptionsContext(Context.Context): >+@@ -141,9 +156,9 @@ class OptionsContext(Context.Context): >+ gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out') >+ gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top') >+ >+- gr.add_option('--no-lock-in-run', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_run') >+- gr.add_option('--no-lock-in-out', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_out') >+- gr.add_option('--no-lock-in-top', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_top') >++ gr.add_option('--no-lock-in-run', action='store_true', default=os.environ.get('NO_LOCK_IN_RUN', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_run') >++ gr.add_option('--no-lock-in-out', action='store_true', default=os.environ.get('NO_LOCK_IN_OUT', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_out') >++ gr.add_option('--no-lock-in-top', action='store_true', default=os.environ.get('NO_LOCK_IN_TOP', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_top') >+ >+ default_prefix = getattr(Context.g_module, 'default_prefix', os.environ.get('PREFIX')) >+ if not default_prefix: >+@@ -282,6 +297,8 @@ class OptionsContext(Context.Context): >+ elif arg != 'options': >+ commands.append(arg) >+ >++ if options.jobs < 1: >++ options.jobs = 1 >+ for name in 'top out destdir prefix bindir libdir'.split(): >+ # those paths are usually expanded from Context.launch_dir >+ if getattr(options, name, None): >+diff --git third_party/waf/waflib/Scripting.py third_party/waf/waflib/Scripting.py >+index 68dccf29ce0..da83a2166a1 100644 >+--- third_party/waf/waflib/Scripting.py >++++ third_party/waf/waflib/Scripting.py >+@@ -306,7 +306,7 @@ def distclean(ctx): >+ >+ # remove a build folder, if any >+ cur = '.' >+- if ctx.options.no_lock_in_top: >++ if os.environ.get('NO_LOCK_IN_TOP') or ctx.options.no_lock_in_top: >+ cur = ctx.options.out >+ >+ try: >+@@ -333,9 +333,9 @@ def distclean(ctx): >+ remove_and_log(env.out_dir, shutil.rmtree) >+ >+ env_dirs = [env.out_dir] >+- if not ctx.options.no_lock_in_top: >++ if not (os.environ.get('NO_LOCK_IN_TOP') or ctx.options.no_lock_in_top): >+ env_dirs.append(env.top_dir) >+- if not ctx.options.no_lock_in_run: >++ if not (os.environ.get('NO_LOCK_IN_RUN') or ctx.options.no_lock_in_run): >+ env_dirs.append(env.run_dir) >+ for k in env_dirs: >+ p = os.path.join(k, Options.lockfile) >+diff --git third_party/waf/waflib/Tools/c_aliases.py third_party/waf/waflib/Tools/c_aliases.py >+index 985e048bdb7..928cfe29caa 100644 >+--- third_party/waf/waflib/Tools/c_aliases.py >++++ third_party/waf/waflib/Tools/c_aliases.py >+@@ -38,7 +38,7 @@ def sniff_features(**kw): >+ :return: the list of features for a task generator processing the source files >+ :rtype: list of string >+ """ >+- exts = get_extensions(kw['source']) >++ exts = get_extensions(kw.get('source', [])) >+ typ = kw['typ'] >+ feats = [] >+ >+@@ -72,7 +72,7 @@ def sniff_features(**kw): >+ feats.append(x + typ) >+ will_link = True >+ if not will_link and not kw.get('features', []): >+- raise Errors.WafError('Cannot link from %r, try passing eg: features="c cprogram"?' % kw) >++ raise Errors.WafError('Unable to determine how to link %r, try adding eg: features="c cshlib"?' % kw) >+ return feats >+ >+ def set_features(kw, typ): >+diff --git third_party/waf/waflib/Tools/c_config.py third_party/waf/waflib/Tools/c_config.py >+index 80580cc9fcb..98187fac2e2 100644 >+--- third_party/waf/waflib/Tools/c_config.py >++++ third_party/waf/waflib/Tools/c_config.py >+@@ -86,6 +86,10 @@ def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=No >+ :type uselib_store: string >+ :param env: config set or conf.env by default >+ :type env: :py:class:`waflib.ConfigSet.ConfigSet` >++ :param force_static: force usage of static libraries >++ :type force_static: bool default False >++ :param posix: usage of POSIX mode for shlex lexical analiysis library >++ :type posix: bool default True >+ """ >+ >+ assert(isinstance(line, str)) >+@@ -103,6 +107,8 @@ def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=No >+ lex.commenters = '' >+ lst = list(lex) >+ >++ so_re = re.compile(r"\.so(?:\.[0-9]+)*$") >++ >+ # append_unique is not always possible >+ # for example, apple flags may require both -arch i386 and -arch ppc >+ uselib = uselib_store >+@@ -144,7 +150,7 @@ def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=No >+ elif x.startswith('-std='): >+ prefix = 'CXXFLAGS' if '++' in x else 'CFLAGS' >+ app(prefix, x) >+- elif x.startswith('+') or x in ('-pthread', '-fPIC', '-fpic', '-fPIE', '-fpie'): >++ elif x.startswith('+') or x in ('-pthread', '-fPIC', '-fpic', '-fPIE', '-fpie', '-flto', '-fno-lto'): >+ app('CFLAGS', x) >+ app('CXXFLAGS', x) >+ app('LINKFLAGS', x) >+@@ -180,7 +186,7 @@ def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=No >+ app('CFLAGS', tmp) >+ app('CXXFLAGS', tmp) >+ app('LINKFLAGS', tmp) >+- elif x.endswith(('.a', '.so', '.dylib', '.lib')): >++ elif x.endswith(('.a', '.dylib', '.lib')) or so_re.search(x): >+ appu('LINKFLAGS', x) # not cool, #762 >+ else: >+ self.to_log('Unhandled flag %r' % x) >+@@ -246,6 +252,8 @@ def exec_cfg(self, kw): >+ * if modversion is given, then return the module version >+ * else, execute the *-config* program with the *args* and *variables* given, and set the flags on the *conf.env.FLAGS_name* variable >+ >++ :param path: the **-config program to use** >++ :type path: list of string >+ :param atleast_pkgconfig_version: minimum pkg-config version to use (disable other tests) >+ :type atleast_pkgconfig_version: string >+ :param package: package name, for example *gtk+-2.0* >+@@ -260,6 +268,12 @@ def exec_cfg(self, kw): >+ :type variables: list of string >+ :param define_variable: additional variables to define (also in conf.env.PKG_CONFIG_DEFINES) >+ :type define_variable: dict(string: string) >++ :param pkg_config_path: paths where pkg-config should search for .pc config files (overrides env.PKG_CONFIG_PATH if exists) >++ :type pkg_config_path: string, list of directories separated by colon >++ :param force_static: force usage of static libraries >++ :type force_static: bool default False >++ :param posix: usage of POSIX mode for shlex lexical analiysis library >++ :type posix: bool default True >+ """ >+ >+ path = Utils.to_list(kw['path']) >+@@ -334,6 +348,7 @@ def check_cfg(self, *k, **kw): >+ """ >+ Checks for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc). >+ This wraps internal calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg` >++ so check exec_cfg parameters descriptions for more details on kw passed >+ >+ A few examples:: >+ >+@@ -1267,10 +1282,11 @@ def multicheck(self, *k, **kw): >+ tasks = [] >+ >+ id_to_task = {} >+- for dct in k: >++ for counter, dct in enumerate(k): >+ x = Task.classes['cfgtask'](bld=bld, env=None) >+ tasks.append(x) >+ x.args = dct >++ x.args['multicheck_counter'] = counter >+ x.bld = bld >+ x.conf = self >+ x.args = dct >+diff --git third_party/waf/waflib/Tools/c_tests.py third_party/waf/waflib/Tools/c_tests.py >+index 7a4094f2450..bdd186c6bc4 100644 >+--- third_party/waf/waflib/Tools/c_tests.py >++++ third_party/waf/waflib/Tools/c_tests.py >+@@ -180,9 +180,15 @@ def check_large_file(self, **kw): >+ ######################################################################################## >+ >+ ENDIAN_FRAGMENT = ''' >++#ifdef _MSC_VER >++#define testshlib_EXPORT __declspec(dllexport) >++#else >++#define testshlib_EXPORT >++#endif >++ >+ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; >+ short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; >+-int use_ascii (int i) { >++int testshlib_EXPORT use_ascii (int i) { >+ return ascii_mm[i] + ascii_ii[i]; >+ } >+ short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; >+@@ -208,12 +214,12 @@ class grep_for_endianness(Task.Task): >+ return -1 >+ >+ @feature('grep_for_endianness') >+-@after_method('process_source') >++@after_method('apply_link') >+ def grep_for_endianness_fun(self): >+ """ >+ Used by the endianness configuration test >+ """ >+- self.create_task('grep_for_endianness', self.compiled_tasks[0].outputs[0]) >++ self.create_task('grep_for_endianness', self.link_task.outputs[0]) >+ >+ @conf >+ def check_endianness(self): >+@@ -223,7 +229,8 @@ def check_endianness(self): >+ tmp = [] >+ def check_msg(self): >+ return tmp[0] >+- self.check(fragment=ENDIAN_FRAGMENT, features='c grep_for_endianness', >++ >++ self.check(fragment=ENDIAN_FRAGMENT, features='c cshlib grep_for_endianness', >+ msg='Checking for endianness', define='ENDIANNESS', tmp=tmp, >+ okmsg=check_msg, confcache=None) >+ return tmp[0] >+diff --git third_party/waf/waflib/Tools/compiler_c.py third_party/waf/waflib/Tools/compiler_c.py >+index 2dba3f82704..931dc57efec 100644 >+--- third_party/waf/waflib/Tools/compiler_c.py >++++ third_party/waf/waflib/Tools/compiler_c.py >+@@ -37,7 +37,7 @@ from waflib.Logs import debug >+ >+ c_compiler = { >+ 'win32': ['msvc', 'gcc', 'clang'], >+-'cygwin': ['gcc'], >++'cygwin': ['gcc', 'clang'], >+ 'darwin': ['clang', 'gcc'], >+ 'aix': ['xlc', 'gcc', 'clang'], >+ 'linux': ['gcc', 'clang', 'icc'], >+diff --git third_party/waf/waflib/Tools/compiler_cxx.py third_party/waf/waflib/Tools/compiler_cxx.py >+index 1af65a226dc..09fca7e4dc6 100644 >+--- third_party/waf/waflib/Tools/compiler_cxx.py >++++ third_party/waf/waflib/Tools/compiler_cxx.py >+@@ -38,7 +38,7 @@ from waflib.Logs import debug >+ >+ cxx_compiler = { >+ 'win32': ['msvc', 'g++', 'clang++'], >+-'cygwin': ['g++'], >++'cygwin': ['g++', 'clang++'], >+ 'darwin': ['clang++', 'g++'], >+ 'aix': ['xlc++', 'g++', 'clang++'], >+ 'linux': ['g++', 'clang++', 'icpc'], >+diff --git third_party/waf/waflib/Tools/fc.py third_party/waf/waflib/Tools/fc.py >+index fd4d39c90ae..7fbd76d3650 100644 >+--- third_party/waf/waflib/Tools/fc.py >++++ third_party/waf/waflib/Tools/fc.py >+@@ -13,8 +13,8 @@ from waflib.TaskGen import extension >+ from waflib.Configure import conf >+ >+ ccroot.USELIB_VARS['fc'] = set(['FCFLAGS', 'DEFINES', 'INCLUDES', 'FCPPFLAGS']) >+-ccroot.USELIB_VARS['fcprogram_test'] = ccroot.USELIB_VARS['fcprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS']) >+-ccroot.USELIB_VARS['fcshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS']) >++ccroot.USELIB_VARS['fcprogram_test'] = ccroot.USELIB_VARS['fcprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'LDFLAGS']) >++ccroot.USELIB_VARS['fcshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'LDFLAGS']) >+ ccroot.USELIB_VARS['fcstlib'] = set(['ARFLAGS', 'LINKDEPS']) >+ >+ @extension('.f','.F','.f90','.F90','.for','.FOR','.f95','.F95','.f03','.F03','.f08','.F08') >+diff --git third_party/waf/waflib/Tools/irixcc.py third_party/waf/waflib/Tools/irixcc.py >+index c3ae1ac915c..0335c13cb61 100644 >+--- third_party/waf/waflib/Tools/irixcc.py >++++ third_party/waf/waflib/Tools/irixcc.py >+@@ -13,22 +13,11 @@ from waflib.Configure import conf >+ @conf >+ def find_irixcc(conf): >+ v = conf.env >+- cc = None >+- if v.CC: >+- cc = v.CC >+- elif 'CC' in conf.environ: >+- cc = conf.environ['CC'] >+- if not cc: >+- cc = conf.find_program('cc', var='CC') >+- if not cc: >+- conf.fatal('irixcc was not found') >+- >++ cc = conf.find_program('cc', var='CC') >+ try: >+ conf.cmd_and_log(cc + ['-version']) >+ except Errors.WafError: >+ conf.fatal('%r -version could not be executed' % cc) >+- >+- v.CC = cc >+ v.CC_NAME = 'irix' >+ >+ @conf >+@@ -57,7 +46,6 @@ def irixcc_common_flags(conf): >+ >+ def configure(conf): >+ conf.find_irixcc() >+- conf.find_cpp() >+ conf.find_ar() >+ conf.irixcc_common_flags() >+ conf.cc_load_tools() >+diff --git third_party/waf/waflib/Tools/javaw.py third_party/waf/waflib/Tools/javaw.py >+index ceb08c28c87..b7f5dd1f87f 100644 >+--- third_party/waf/waflib/Tools/javaw.py >++++ third_party/waf/waflib/Tools/javaw.py >+@@ -251,7 +251,7 @@ def use_javac_files(self): >+ base_node = tg.path.get_bld() >+ >+ self.use_lst.append(base_node.abspath()) >+- self.javac_task.dep_nodes.extend([x for x in base_node.ant_glob(JAR_RE, remove=False, quiet=True)]) >++ self.javac_task.dep_nodes.extend([dx for dx in base_node.ant_glob(JAR_RE, remove=False, quiet=True)]) >+ >+ for tsk in tg.tasks: >+ self.javac_task.set_run_after(tsk) >+diff --git third_party/waf/waflib/Tools/python.py third_party/waf/waflib/Tools/python.py >+index 7c45a76ffd2..b1c8dd01285 100644 >+--- third_party/waf/waflib/Tools/python.py >++++ third_party/waf/waflib/Tools/python.py >+@@ -620,7 +620,7 @@ def configure(conf): >+ v.PYO = getattr(Options.options, 'pyo', 1) >+ >+ try: >+- v.PYTAG = conf.cmd_and_log(conf.env.PYTHON + ['-c', "import imp;print(imp.get_tag())"]).strip() >++ v.PYTAG = conf.cmd_and_log(conf.env.PYTHON + ['-c', "import sys\ntry:\n print(sys.implementation.cache_tag)\nexcept AttributeError:\n import imp\n print(imp.get_tag())\n"]).strip() >+ except Errors.WafError: >+ pass >+ >+diff --git third_party/waf/waflib/Tools/qt5.py third_party/waf/waflib/Tools/qt5.py >+index 287c25374a4..99e021bae61 100644 >+--- third_party/waf/waflib/Tools/qt5.py >++++ third_party/waf/waflib/Tools/qt5.py >+@@ -482,8 +482,8 @@ def configure(self): >+ self.fatal('No CXX compiler defined: did you forget to configure compiler_cxx first?') >+ >+ # Qt5 may be compiled with '-reduce-relocations' which requires dependent programs to have -fPIE or -fPIC? >+- frag = '#include <QApplication>\nint main(int argc, char **argv) {return 0;}\n' >+- uses = 'QT5CORE QT5WIDGETS QT5GUI' >++ frag = '#include <QMap>\nint main(int argc, char **argv) {QMap<int,int> m;return m.keys().size();}\n' >++ uses = 'QT5CORE' >+ for flag in [[], '-fPIE', '-fPIC', '-std=c++11' , ['-std=c++11', '-fPIE'], ['-std=c++11', '-fPIC']]: >+ msg = 'See if Qt files compile ' >+ if flag: >+@@ -499,7 +499,7 @@ def configure(self): >+ >+ # FreeBSD does not add /usr/local/lib and the pkg-config files do not provide it either :-/ >+ if Utils.unversioned_sys_platform() == 'freebsd': >+- frag = '#include <QApplication>\nint main(int argc, char **argv) { QApplication app(argc, argv); return NULL != (void*) (&app);}\n' >++ frag = '#include <QMap>\nint main(int argc, char **argv) {QMap<int,int> m;return m.keys().size();}\n' >+ try: >+ self.check(features='qt5 cxx cxxprogram', use=uses, fragment=frag, msg='Can we link Qt programs on FreeBSD directly?') >+ except self.errors.ConfigurationError: >+diff --git third_party/waf/waflib/Utils.py third_party/waf/waflib/Utils.py >+index 7472226da58..fc64fa05154 100644 >+--- third_party/waf/waflib/Utils.py >++++ third_party/waf/waflib/Utils.py >+@@ -891,7 +891,7 @@ def run_prefork_process(cmd, kwargs, cargs): >+ """ >+ Delegates process execution to a pre-forked process instance. >+ """ >+- if not 'env' in kwargs: >++ if not kwargs.get('env'): >+ kwargs['env'] = dict(os.environ) >+ try: >+ obj = base64.b64encode(cPickle.dumps([cmd, kwargs, cargs])) >+diff --git third_party/waf/waflib/extras/clang_compilation_database.py third_party/waf/waflib/extras/clang_compilation_database.py >+index 4d9b5e275ae..ff71f22ecfd 100644 >+--- third_party/waf/waflib/extras/clang_compilation_database.py >++++ third_party/waf/waflib/extras/clang_compilation_database.py >+@@ -1,6 +1,7 @@ >+ #!/usr/bin/env python >+ # encoding: utf-8 >+ # Christoph Koke, 2013 >++# Alibek Omarov, 2019 >+ >+ """ >+ Writes the c and cpp compile commands into build/compile_commands.json >+@@ -8,14 +9,23 @@ see http://clang.llvm.org/docs/JSONCompilationDatabase.html >+ >+ Usage: >+ >+- def configure(conf): >+- conf.load('compiler_cxx') >+- ... >+- conf.load('clang_compilation_database') >++ Load this tool in `options` to be able to generate database >++ by request in command-line and before build: >++ >++ $ waf clangdb >++ >++ def options(opt): >++ opt.load('clang_compilation_database') >++ >++ Otherwise, load only in `configure` to generate it always before build. >++ >++ def configure(conf): >++ conf.load('compiler_cxx') >++ ... >++ conf.load('clang_compilation_database') >+ """ >+ >+-import sys, os, json, shlex, pipes >+-from waflib import Logs, TaskGen, Task >++from waflib import Logs, TaskGen, Task, Build, Scripting >+ >+ Task.Task.keep_last_cmd = True >+ >+@@ -23,63 +33,103 @@ Task.Task.keep_last_cmd = True >+ @TaskGen.after_method('process_use') >+ def collect_compilation_db_tasks(self): >+ "Add a compilation database entry for compiled tasks" >+- try: >+- clang_db = self.bld.clang_compilation_database_tasks >+- except AttributeError: >+- clang_db = self.bld.clang_compilation_database_tasks = [] >+- self.bld.add_post_fun(write_compilation_database) >++ if not isinstance(self.bld, ClangDbContext): >++ return >+ >+ tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y) >+ for task in getattr(self, 'compiled_tasks', []): >+ if isinstance(task, tup): >+- clang_db.append(task) >+- >+-def write_compilation_database(ctx): >+- "Write the clang compilation database as JSON" >+- database_file = ctx.bldnode.make_node('compile_commands.json') >+- Logs.info('Build commands will be stored in %s', database_file.path_from(ctx.path)) >+- try: >+- root = json.load(database_file) >+- except IOError: >+- root = [] >+- clang_db = dict((x['file'], x) for x in root) >+- for task in getattr(ctx, 'clang_compilation_database_tasks', []): >++ self.bld.clang_compilation_database_tasks.append(task) >++ >++class ClangDbContext(Build.BuildContext): >++ '''generates compile_commands.json by request''' >++ cmd = 'clangdb' >++ clang_compilation_database_tasks = [] >++ >++ def write_compilation_database(self): >++ """ >++ Write the clang compilation database as JSON >++ """ >++ database_file = self.bldnode.make_node('compile_commands.json') >++ Logs.info('Build commands will be stored in %s', database_file.path_from(self.path)) >+ try: >+- cmd = task.last_cmd >+- except AttributeError: >+- continue >+- directory = getattr(task, 'cwd', ctx.variant_dir) >+- f_node = task.inputs[0] >+- filename = os.path.relpath(f_node.abspath(), directory) >+- entry = { >+- "directory": directory, >+- "arguments": cmd, >+- "file": filename, >+- } >+- clang_db[filename] = entry >+- root = list(clang_db.values()) >+- database_file.write(json.dumps(root, indent=2)) >+- >+-# Override the runnable_status function to do a dummy/dry run when the file doesn't need to be compiled. >+-# This will make sure compile_commands.json is always fully up to date. >+-# Previously you could end up with a partial compile_commands.json if the build failed. >+-for x in ('c', 'cxx'): >+- if x not in Task.classes: >+- continue >+- >+- t = Task.classes[x] >+- >+- def runnable_status(self): >+- def exec_command(cmd, **kw): >+- pass >+- >+- run_status = self.old_runnable_status() >+- if run_status == Task.SKIP_ME: >+- setattr(self, 'old_exec_command', getattr(self, 'exec_command', None)) >+- setattr(self, 'exec_command', exec_command) >+- self.run() >+- setattr(self, 'exec_command', getattr(self, 'old_exec_command', None)) >+- return run_status >+- >+- setattr(t, 'old_runnable_status', getattr(t, 'runnable_status', None)) >+- setattr(t, 'runnable_status', runnable_status) >++ root = database_file.read_json() >++ except IOError: >++ root = [] >++ clang_db = dict((x['file'], x) for x in root) >++ for task in self.clang_compilation_database_tasks: >++ try: >++ cmd = task.last_cmd >++ except AttributeError: >++ continue >++ f_node = task.inputs[0] >++ filename = f_node.path_from(task.get_cwd()) >++ entry = { >++ "directory": task.get_cwd().abspath(), >++ "arguments": cmd, >++ "file": filename, >++ } >++ clang_db[filename] = entry >++ root = list(clang_db.values()) >++ database_file.write_json(root) >++ >++ def execute(self): >++ """ >++ Build dry run >++ """ >++ self.restore() >++ >++ if not self.all_envs: >++ self.load_envs() >++ >++ self.recurse([self.run_dir]) >++ self.pre_build() >++ >++ # we need only to generate last_cmd, so override >++ # exec_command temporarily >++ def exec_command(self, *k, **kw): >++ return 0 >++ >++ for g in self.groups: >++ for tg in g: >++ try: >++ f = tg.post >++ except AttributeError: >++ pass >++ else: >++ f() >++ >++ if isinstance(tg, Task.Task): >++ lst = [tg] >++ else: lst = tg.tasks >++ for tsk in lst: >++ tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y) >++ if isinstance(tsk, tup): >++ old_exec = tsk.exec_command >++ tsk.exec_command = exec_command >++ tsk.run() >++ tsk.exec_command = old_exec >++ >++ self.write_compilation_database() >++ >++EXECUTE_PATCHED = False >++def patch_execute(): >++ global EXECUTE_PATCHED >++ >++ if EXECUTE_PATCHED: >++ return >++ >++ def new_execute_build(self): >++ """ >++ Invoke clangdb command before build >++ """ >++ if self.cmd.startswith('build'): >++ Scripting.run_command('clangdb') >++ >++ old_execute_build(self) >++ >++ old_execute_build = getattr(Build.BuildContext, 'execute_build', None) >++ setattr(Build.BuildContext, 'execute_build', new_execute_build) >++ EXECUTE_PATCHED = True >++ >++patch_execute() >+diff --git third_party/waf/waflib/extras/doxygen.py third_party/waf/waflib/extras/doxygen.py >+index 20cd9e1a852..de75bc2738a 100644 >+--- third_party/waf/waflib/extras/doxygen.py >++++ third_party/waf/waflib/extras/doxygen.py >+@@ -69,6 +69,7 @@ def parse_doxy(txt): >+ class doxygen(Task.Task): >+ vars = ['DOXYGEN', 'DOXYFLAGS'] >+ color = 'BLUE' >++ ext_in = [ '.py', '.c', '.h', '.java', '.pb.cc' ] >+ >+ def runnable_status(self): >+ ''' >+diff --git third_party/waf/waflib/extras/gccdeps.py third_party/waf/waflib/extras/gccdeps.py >+index bfabe72e6fd..c3a809e252a 100644 >+--- third_party/waf/waflib/extras/gccdeps.py >++++ third_party/waf/waflib/extras/gccdeps.py >+@@ -27,7 +27,7 @@ if not c_preproc.go_absolute: >+ gccdeps_flags = ['-MMD'] >+ >+ # Third-party tools are allowed to add extra names in here with append() >+-supported_compilers = ['gcc', 'icc', 'clang'] >++supported_compilers = ['gas', 'gcc', 'icc', 'clang'] >+ >+ def scan(self): >+ if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: >+@@ -175,14 +175,14 @@ def wrap_compiled_task(classname): >+ derived_class.scan = scan >+ derived_class.sig_implicit_deps = sig_implicit_deps >+ >+-for k in ('c', 'cxx'): >++for k in ('asm', 'c', 'cxx'): >+ if k in Task.classes: >+ wrap_compiled_task(k) >+ >+ @before_method('process_source') >+ @feature('force_gccdeps') >+ def force_gccdeps(self): >+- self.env.ENABLE_GCCDEPS = ['c', 'cxx'] >++ self.env.ENABLE_GCCDEPS = ['asm', 'c', 'cxx'] >+ >+ def configure(conf): >+ # in case someone provides a --enable-gccdeps command-line option >+@@ -191,6 +191,15 @@ def configure(conf): >+ >+ global gccdeps_flags >+ flags = conf.env.GCCDEPS_FLAGS or gccdeps_flags >++ if conf.env.ASM_NAME in supported_compilers: >++ try: >++ conf.check(fragment='', features='asm force_gccdeps', asflags=flags, compile_filename='test.S', msg='Checking for asm flags %r' % ''.join(flags)) >++ except Errors.ConfigurationError: >++ pass >++ else: >++ conf.env.append_value('ASFLAGS', flags) >++ conf.env.append_unique('ENABLE_GCCDEPS', 'asm') >++ >+ if conf.env.CC_NAME in supported_compilers: >+ try: >+ conf.check(fragment='int main() { return 0; }', features='c force_gccdeps', cflags=flags, msg='Checking for c flags %r' % ''.join(flags)) >+diff --git third_party/waf/waflib/extras/javatest.py third_party/waf/waflib/extras/javatest.py >+index 979b8d8242d..76d40edf250 100755 >+--- third_party/waf/waflib/extras/javatest.py >++++ third_party/waf/waflib/extras/javatest.py >+@@ -1,6 +1,6 @@ >+ #! /usr/bin/env python >+ # encoding: utf-8 >+-# Federico Pellegrin, 2017 (fedepell) >++# Federico Pellegrin, 2019 (fedepell) >+ >+ """ >+ Provides Java Unit test support using :py:class:`waflib.Tools.waf_unit_test.utest` >+@@ -11,6 +11,10 @@ standard waf unit test environment. It has been tested with TestNG and JUnit >+ but should be easily expandable to other frameworks given the flexibility of >+ ut_str provided by the standard waf unit test environment. >+ >++The extra takes care also of managing non-java dependencies (ie. C/C++ libraries >++using JNI or Python modules via JEP) and setting up the environment needed to run >++them. >++ >+ Example usage: >+ >+ def options(opt): >+@@ -20,15 +24,15 @@ def configure(conf): >+ conf.load('java javatest') >+ >+ def build(bld): >+- >++ >+ [ ... mainprog is built here ... ] >+ >+ bld(features = 'javac javatest', >+- srcdir = 'test/', >+- outdir = 'test', >++ srcdir = 'test/', >++ outdir = 'test', >+ sourcepath = ['test'], >+- classpath = [ 'src' ], >+- basedir = 'test', >++ classpath = [ 'src' ], >++ basedir = 'test', >+ use = ['JAVATEST', 'mainprog'], # mainprog is the program being tested in src/ >+ ut_str = 'java -cp ${CLASSPATH} ${JTRUNNER} ${SRC}', >+ jtest_source = bld.path.ant_glob('test/*.xml'), >+@@ -53,10 +57,107 @@ The runner class presence on the system is checked for at configuration stage. >+ """ >+ >+ import os >+-from waflib import Task, TaskGen, Options >++from waflib import Task, TaskGen, Options, Errors, Utils, Logs >++from waflib.Tools import ccroot >++ >++JAR_RE = '**/*' >++ >++def _process_use_rec(self, name): >++ """ >++ Recursively process ``use`` for task generator with name ``name``.. >++ Used by javatest_process_use. >++ """ >++ if name in self.javatest_use_not or name in self.javatest_use_seen: >++ return >++ try: >++ tg = self.bld.get_tgen_by_name(name) >++ except Errors.WafError: >++ self.javatest_use_not.add(name) >++ return >++ >++ self.javatest_use_seen.append(name) >++ tg.post() >++ >++ for n in self.to_list(getattr(tg, 'use', [])): >++ _process_use_rec(self, n) >++ >++@TaskGen.feature('javatest') >++@TaskGen.after_method('process_source', 'apply_link', 'use_javac_files') >++def javatest_process_use(self): >++ """ >++ Process the ``use`` attribute which contains a list of task generator names and store >++ paths that later is used to populate the unit test runtime environment. >++ """ >++ self.javatest_use_not = set() >++ self.javatest_use_seen = [] >++ self.javatest_libpaths = [] # strings or Nodes >++ self.javatest_pypaths = [] # strings or Nodes >++ self.javatest_dep_nodes = [] >++ >++ names = self.to_list(getattr(self, 'use', [])) >++ for name in names: >++ _process_use_rec(self, name) >++ >++ def extend_unique(lst, varlst): >++ ext = [] >++ for x in varlst: >++ if x not in lst: >++ ext.append(x) >++ lst.extend(ext) >++ >++ # Collect type specific info needed to construct a valid runtime environment >++ # for the test. >++ for name in self.javatest_use_seen: >++ tg = self.bld.get_tgen_by_name(name) >++ >++ # Python-Java embedding crosstools such as JEP >++ if 'py' in tg.features: >++ # Python dependencies are added to PYTHONPATH >++ pypath = getattr(tg, 'install_from', tg.path) >++ >++ if 'buildcopy' in tg.features: >++ # Since buildcopy is used we assume that PYTHONPATH in build should be used, >++ # not source >++ extend_unique(self.javatest_pypaths, [pypath.get_bld().abspath()]) >++ >++ # Add buildcopy output nodes to dependencies >++ extend_unique(self.javatest_dep_nodes, [o for task in getattr(tg, 'tasks', []) for o in getattr(task, 'outputs', [])]) >++ else: >++ # If buildcopy is not used, depend on sources instead >++ extend_unique(self.javatest_dep_nodes, tg.source) >++ extend_unique(self.javatest_pypaths, [pypath.abspath()]) >++ >++ >++ if getattr(tg, 'link_task', None): >++ # For tasks with a link_task (C, C++, D et.c.) include their library paths: >++ if not isinstance(tg.link_task, ccroot.stlink_task): >++ extend_unique(self.javatest_dep_nodes, tg.link_task.outputs) >++ extend_unique(self.javatest_libpaths, tg.link_task.env.LIBPATH) >++ >++ if 'pyext' in tg.features: >++ # If the taskgen is extending Python we also want to add the interpreter libpath. >++ extend_unique(self.javatest_libpaths, tg.link_task.env.LIBPATH_PYEXT) >++ else: >++ # Only add to libpath if the link task is not a Python extension >++ extend_unique(self.javatest_libpaths, [tg.link_task.outputs[0].parent.abspath()]) >++ >++ if 'javac' in tg.features or 'jar' in tg.features: >++ if hasattr(tg, 'jar_task'): >++ # For Java JAR tasks depend on generated JAR >++ extend_unique(self.javatest_dep_nodes, tg.jar_task.outputs) >++ else: >++ # For Java non-JAR ones we need to glob generated files (Java output files are not predictable) >++ if hasattr(tg, 'outdir'): >++ base_node = tg.outdir >++ else: >++ base_node = tg.path.get_bld() >++ >++ self.javatest_dep_nodes.extend([dx for dx in base_node.ant_glob(JAR_RE, remove=False, quiet=True)]) >++ >++ >+ >+ @TaskGen.feature('javatest') >+-@TaskGen.after_method('apply_java', 'use_javac_files', 'set_classpath') >++@TaskGen.after_method('apply_java', 'use_javac_files', 'set_classpath', 'javatest_process_use') >+ def make_javatest(self): >+ """ >+ Creates a ``utest`` task with a populated environment for Java Unit test execution >+@@ -65,6 +166,9 @@ def make_javatest(self): >+ tsk = self.create_task('utest') >+ tsk.set_run_after(self.javac_task) >+ >++ # Dependencies from recursive use analysis >++ tsk.dep_nodes.extend(self.javatest_dep_nodes) >++ >+ # Put test input files as waf_unit_test relies on that for some prints and log generation >+ # If jtest_source is there, this is specially useful for passing XML for TestNG >+ # that contain test specification, use that as inputs, otherwise test sources >+@@ -97,6 +201,21 @@ def make_javatest(self): >+ >+ if not hasattr(self, 'ut_env'): >+ self.ut_env = dict(os.environ) >++ def add_paths(var, lst): >++ # Add list of paths to a variable, lst can contain strings or nodes >++ lst = [ str(n) for n in lst ] >++ Logs.debug("ut: %s: Adding paths %s=%s", self, var, lst) >++ self.ut_env[var] = os.pathsep.join(lst) + os.pathsep + self.ut_env.get(var, '') >++ >++ add_paths('PYTHONPATH', self.javatest_pypaths) >++ >++ if Utils.is_win32: >++ add_paths('PATH', self.javatest_libpaths) >++ elif Utils.unversioned_sys_platform() == 'darwin': >++ add_paths('DYLD_LIBRARY_PATH', self.javatest_libpaths) >++ add_paths('LD_LIBRARY_PATH', self.javatest_libpaths) >++ else: >++ add_paths('LD_LIBRARY_PATH', self.javatest_libpaths) >+ >+ def configure(ctx): >+ cp = ctx.env.CLASSPATH or '.' >+diff --git third_party/waf/waflib/extras/msvc_pdb.py third_party/waf/waflib/extras/msvc_pdb.py >+new file mode 100644 >+index 00000000000..077656b4f7e >+--- /dev/null >++++ third_party/waf/waflib/extras/msvc_pdb.py >+@@ -0,0 +1,46 @@ >++#!/usr/bin/env python >++# encoding: utf-8 >++# Rafaël Kooi 2019 >++ >++from waflib import TaskGen >++ >++@TaskGen.feature('c', 'cxx', 'fc') >++@TaskGen.after_method('propagate_uselib_vars') >++def add_pdb_per_object(self): >++ """For msvc/fortran, specify a unique compile pdb per object, to work >++ around LNK4099. Flags are updated with a unique /Fd flag based on the >++ task output name. This is separate from the link pdb. >++ """ >++ if not hasattr(self, 'compiled_tasks'): >++ return >++ >++ link_task = getattr(self, 'link_task', None) >++ >++ for task in self.compiled_tasks: >++ if task.inputs and task.inputs[0].name.lower().endswith('.rc'): >++ continue >++ >++ add_pdb = False >++ for flagname in ('CFLAGS', 'CXXFLAGS', 'FCFLAGS'): >++ # several languages may be used at once >++ for flag in task.env[flagname]: >++ if flag[1:].lower() == 'zi': >++ add_pdb = True >++ break >++ >++ if add_pdb: >++ node = task.outputs[0].change_ext('.pdb') >++ pdb_flag = '/Fd:' + node.abspath() >++ >++ for flagname in ('CFLAGS', 'CXXFLAGS', 'FCFLAGS'): >++ buf = [pdb_flag] >++ for flag in task.env[flagname]: >++ if flag[1:3] == 'Fd' or flag[1:].lower() == 'fs' or flag[1:].lower() == 'mp': >++ continue >++ buf.append(flag) >++ task.env[flagname] = buf >++ >++ if link_task and not node in link_task.dep_nodes: >++ link_task.dep_nodes.append(node) >++ if not node in task.outputs: >++ task.outputs.append(node) >+diff --git third_party/waf/waflib/extras/pytest.py third_party/waf/waflib/extras/pytest.py >+index 7dd5a1a087a..fc9ad1c23e4 100644 >+--- third_party/waf/waflib/extras/pytest.py >++++ third_party/waf/waflib/extras/pytest.py >+@@ -40,6 +40,8 @@ the following environment variables for the `pytest` test runner: >+ >+ - `pytest_libpath` attribute is used to manually specify additional linker paths. >+ >++3. Java class search path (CLASSPATH) of any Java/Javalike dependency >++ >+ Note: `pytest` cannot automatically determine the correct `PYTHONPATH` for `pyext` taskgens >+ because the extension might be part of a Python package or used standalone: >+ >+@@ -119,6 +121,7 @@ def pytest_process_use(self): >+ self.pytest_use_seen = [] >+ self.pytest_paths = [] # strings or Nodes >+ self.pytest_libpaths = [] # strings or Nodes >++ self.pytest_javapaths = [] # strings or Nodes >+ self.pytest_dep_nodes = [] >+ >+ names = self.to_list(getattr(self, 'use', [])) >+@@ -157,6 +160,17 @@ def pytest_process_use(self): >+ extend_unique(self.pytest_dep_nodes, tg.source) >+ extend_unique(self.pytest_paths, [pypath.abspath()]) >+ >++ if 'javac' in tg.features: >++ # If a JAR is generated point to that, otherwise to directory >++ if getattr(tg, 'jar_task', None): >++ extend_unique(self.pytest_javapaths, [tg.jar_task.outputs[0].abspath()]) >++ else: >++ extend_unique(self.pytest_javapaths, [tg.path.get_bld()]) >++ >++ # And add respective dependencies if present >++ if tg.use_lst: >++ extend_unique(self.pytest_javapaths, tg.use_lst) >++ >+ if getattr(tg, 'link_task', None): >+ # For tasks with a link_task (C, C++, D et.c.) include their library paths: >+ if not isinstance(tg.link_task, ccroot.stlink_task): >+@@ -212,8 +226,9 @@ def make_pytest(self): >+ Logs.debug("ut: %s: Adding paths %s=%s", self, var, lst) >+ self.ut_env[var] = os.pathsep.join(lst) + os.pathsep + self.ut_env.get(var, '') >+ >+- # Prepend dependency paths to PYTHONPATH and LD_LIBRARY_PATH >++ # Prepend dependency paths to PYTHONPATH, CLASSPATH and LD_LIBRARY_PATH >+ add_paths('PYTHONPATH', self.pytest_paths) >++ add_paths('CLASSPATH', self.pytest_javapaths) >+ >+ if Utils.is_win32: >+ add_paths('PATH', self.pytest_libpaths) >+diff --git third_party/waf/waflib/extras/wafcache.py third_party/waf/waflib/extras/wafcache.py >+new file mode 100644 >+index 00000000000..8b9567faf14 >+--- /dev/null >++++ third_party/waf/waflib/extras/wafcache.py >+@@ -0,0 +1,524 @@ >++#! /usr/bin/env python >++# encoding: utf-8 >++# Thomas Nagy, 2019 (ita) >++ >++""" >++Filesystem-based cache system to share and re-use build artifacts >++ >++Cache access operations (copy to and from) are delegated to >++independent pre-forked worker subprocesses. >++ >++The following environment variables may be set: >++* WAFCACHE: several possibilities: >++ - File cache: >++ absolute path of the waf cache (~/.cache/wafcache_user, >++ where `user` represents the currently logged-in user) >++ - URL to a cache server, for example: >++ export WAFCACHE=http://localhost:8080/files/ >++ in that case, GET/POST requests are made to urls of the form >++ http://localhost:8080/files/000000000/0 (cache management is then up to the server) >++ - GCS or S3 bucket >++ gs://my-bucket/ >++ s3://my-bucket/ >++* WAFCACHE_NO_PUSH: if set, disables pushing to the cache >++* WAFCACHE_VERBOSITY: if set, displays more detailed cache operations >++ >++File cache specific options: >++ Files are copied using hard links by default; if the cache is located >++ onto another partition, the system switches to file copies instead. >++* WAFCACHE_TRIM_MAX_FOLDER: maximum amount of tasks to cache (1M) >++* WAFCACHE_EVICT_MAX_BYTES: maximum amount of cache size in bytes (10GB) >++* WAFCACHE_EVICT_INTERVAL_MINUTES: minimum time interval to try >++ and trim the cache (3 minutess) >++Usage:: >++ >++ def build(bld): >++ bld.load('wafcache') >++ ... >++ >++To troubleshoot:: >++ >++ waf clean build --zones=wafcache >++""" >++ >++import atexit, base64, errno, fcntl, getpass, os, shutil, sys, time, traceback, urllib3 >++try: >++ import subprocess32 as subprocess >++except ImportError: >++ import subprocess >++ >++base_cache = os.path.expanduser('~/.cache/') >++if not os.path.isdir(base_cache): >++ base_cache = '/tmp/' >++default_wafcache_dir = os.path.join(base_cache, 'wafcache_' + getpass.getuser()) >++ >++CACHE_DIR = os.environ.get('WAFCACHE', default_wafcache_dir) >++TRIM_MAX_FOLDERS = int(os.environ.get('WAFCACHE_TRIM_MAX_FOLDER', 1000000)) >++EVICT_INTERVAL_MINUTES = int(os.environ.get('WAFCACHE_EVICT_INTERVAL_MINUTES', 3)) >++EVICT_MAX_BYTES = int(os.environ.get('WAFCACHE_EVICT_MAX_BYTES', 10**10)) >++WAFCACHE_NO_PUSH = 1 if os.environ.get('WAFCACHE_NO_PUSH') else 0 >++WAFCACHE_VERBOSITY = 1 if os.environ.get('WAFCACHE_VERBOSITY') else 0 >++OK = "ok" >++ >++try: >++ import cPickle >++except ImportError: >++ import pickle as cPickle >++ >++if __name__ != '__main__': >++ from waflib import Task, Logs, Utils, Build >++ >++def can_retrieve_cache(self): >++ """ >++ New method for waf Task classes >++ """ >++ if not self.outputs: >++ return False >++ >++ self.cached = False >++ >++ sig = self.signature() >++ ssig = Utils.to_hex(self.uid() + sig) >++ >++ files_to = [node.abspath() for node in self.outputs] >++ err = cache_command(ssig, [], files_to) >++ if err.startswith(OK): >++ if WAFCACHE_VERBOSITY: >++ Logs.pprint('CYAN', ' Fetched %r from cache' % files_to) >++ else: >++ Logs.debug('wafcache: fetched %r from cache', files_to) >++ else: >++ if WAFCACHE_VERBOSITY: >++ Logs.pprint('YELLOW', ' No cache entry %s' % files_to) >++ else: >++ Logs.debug('wafcache: No cache entry %s: %s', files_to, err) >++ return False >++ >++ self.cached = True >++ return True >++ >++def put_files_cache(self): >++ """ >++ New method for waf Task classes >++ """ >++ if WAFCACHE_NO_PUSH or getattr(self, 'cached', None) or not self.outputs: >++ return >++ >++ bld = self.generator.bld >++ sig = self.signature() >++ ssig = Utils.to_hex(self.uid() + sig) >++ >++ files_from = [node.abspath() for node in self.outputs] >++ err = cache_command(ssig, files_from, []) >++ >++ if err.startswith(OK): >++ if WAFCACHE_VERBOSITY: >++ Logs.pprint('CYAN', ' Successfully uploaded %s to cache' % files_from) >++ else: >++ Logs.debug('wafcache: Successfully uploaded %r to cache', files_from) >++ else: >++ if WAFCACHE_VERBOSITY: >++ Logs.pprint('RED', ' Error caching step results %s: %s' % (files_from, err)) >++ else: >++ Logs.debug('wafcache: Error caching results %s: %s', files_from, err) >++ >++ bld.task_sigs[self.uid()] = self.cache_sig >++ >++def hash_env_vars(self, env, vars_lst): >++ """ >++ Reimplement BuildContext.hash_env_vars so that the resulting hash does not depend on local paths >++ """ >++ if not env.table: >++ env = env.parent >++ if not env: >++ return Utils.SIG_NIL >++ >++ idx = str(id(env)) + str(vars_lst) >++ try: >++ cache = self.cache_env >++ except AttributeError: >++ cache = self.cache_env = {} >++ else: >++ try: >++ return self.cache_env[idx] >++ except KeyError: >++ pass >++ >++ v = str([env[a] for a in vars_lst]) >++ v = v.replace(self.srcnode.abspath().__repr__()[:-1], '') >++ m = Utils.md5() >++ m.update(v.encode()) >++ ret = m.digest() >++ >++ Logs.debug('envhash: %r %r', ret, v) >++ >++ cache[idx] = ret >++ >++ return ret >++ >++def uid(self): >++ """ >++ Reimplement Task.uid() so that the signature does not depend on local paths >++ """ >++ try: >++ return self.uid_ >++ except AttributeError: >++ m = Utils.md5() >++ src = self.generator.bld.srcnode >++ up = m.update >++ up(self.__class__.__name__.encode()) >++ for x in self.inputs + self.outputs: >++ up(x.path_from(src).encode()) >++ self.uid_ = m.digest() >++ return self.uid_ >++ >++ >++def make_cached(cls): >++ """ >++ Enable the waf cache for a given task class >++ """ >++ if getattr(cls, 'nocache', None) or getattr(cls, 'has_cache', False): >++ return >++ >++ m1 = getattr(cls, 'run', None) >++ def run(self): >++ if getattr(self, 'nocache', False): >++ return m1(self) >++ if self.can_retrieve_cache(): >++ return 0 >++ return m1(self) >++ cls.run = run >++ >++ m2 = getattr(cls, 'post_run', None) >++ def post_run(self): >++ if getattr(self, 'nocache', False): >++ return m2(self) >++ ret = m2(self) >++ self.put_files_cache() >++ if hasattr(self, 'chmod'): >++ for node in self.outputs: >++ os.chmod(node.abspath(), self.chmod) >++ return ret >++ cls.post_run = post_run >++ cls.has_cache = True >++ >++process_pool = [] >++def get_process(): >++ """ >++ Returns a worker process that can process waf cache commands >++ The worker process is assumed to be returned to the process pool when unused >++ """ >++ try: >++ return process_pool.pop() >++ except IndexError: >++ filepath = os.path.dirname(os.path.abspath(__file__)) + os.sep + 'wafcache.py' >++ cmd = [sys.executable, '-c', Utils.readf(filepath)] >++ return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0) >++ >++def atexit_pool(): >++ for k in process_pool: >++ try: >++ os.kill(k.pid, 9) >++ except OSError: >++ pass >++ else: >++ k.wait() >++atexit.register(atexit_pool) >++ >++def build(bld): >++ """ >++ Called during the build process to enable file caching >++ """ >++ if process_pool: >++ # already called once >++ return >++ >++ for x in range(bld.jobs): >++ process_pool.append(get_process()) >++ >++ Task.Task.can_retrieve_cache = can_retrieve_cache >++ Task.Task.put_files_cache = put_files_cache >++ Task.Task.uid = uid >++ Build.BuildContext.hash_env_vars = hash_env_vars >++ for x in reversed(list(Task.classes.values())): >++ make_cached(x) >++ >++def cache_command(sig, files_from, files_to): >++ """ >++ Create a command for cache worker processes, returns a pickled >++ base64-encoded tuple containing the task signature, a list of files to >++ cache and a list of files files to get from cache (one of the lists >++ is assumed to be empty) >++ """ >++ proc = get_process() >++ >++ obj = base64.b64encode(cPickle.dumps([sig, files_from, files_to])) >++ proc.stdin.write(obj) >++ proc.stdin.write('\n'.encode()) >++ proc.stdin.flush() >++ obj = proc.stdout.readline() >++ if not obj: >++ raise OSError('Preforked sub-process %r died' % proc.pid) >++ process_pool.append(proc) >++ return cPickle.loads(base64.b64decode(obj)) >++ >++try: >++ copyfun = os.link >++except NameError: >++ copyfun = shutil.copy2 >++ >++def atomic_copy(orig, dest): >++ """ >++ Copy files to the cache, the operation is atomic for a given file >++ """ >++ global copyfun >++ tmp = dest + '.tmp' >++ up = os.path.dirname(dest) >++ try: >++ os.makedirs(up) >++ except OSError: >++ pass >++ >++ try: >++ copyfun(orig, tmp) >++ except OSError as e: >++ if e.errno == errno.EXDEV: >++ copyfun = shutil.copy2 >++ copyfun(orig, tmp) >++ else: >++ raise >++ os.rename(tmp, dest) >++ >++def lru_trim(): >++ """ >++ the cache folders take the form: >++ `CACHE_DIR/0b/0b180f82246d726ece37c8ccd0fb1cde2650d7bfcf122ec1f169079a3bfc0ab9` >++ they are listed in order of last access, and then removed >++ until the amount of folders is within TRIM_MAX_FOLDERS and the total space >++ taken by files is less than EVICT_MAX_BYTES >++ """ >++ lst = [] >++ for up in os.listdir(CACHE_DIR): >++ if len(up) == 2: >++ sub = os.path.join(CACHE_DIR, up) >++ for hval in os.listdir(sub): >++ path = os.path.join(sub, hval) >++ >++ size = 0 >++ for fname in os.listdir(path): >++ size += os.lstat(os.path.join(path, fname)).st_size >++ lst.append((os.stat(path).st_mtime, size, path)) >++ >++ lst.sort(key=lambda x: x[0]) >++ lst.reverse() >++ >++ tot = sum(x[1] for x in lst) >++ while tot > EVICT_MAX_BYTES or len(lst) > TRIM_MAX_FOLDERS: >++ _, tmp_size, path = lst.pop() >++ tot -= tmp_size >++ >++ tmp = path + '.tmp' >++ try: >++ shutil.rmtree(tmp) >++ except OSError: >++ pass >++ try: >++ os.rename(path, tmp) >++ except OSError: >++ sys.stderr.write('Could not rename %r to %r' % (path, tmp)) >++ else: >++ try: >++ shutil.rmtree(tmp) >++ except OSError: >++ sys.stderr.write('Could not remove %r' % tmp) >++ sys.stderr.write("Cache trimmed: %r bytes in %r folders left\n" % (tot, len(lst))) >++ >++ >++def lru_evict(): >++ """ >++ Reduce the cache size >++ """ >++ lockfile = os.path.join(CACHE_DIR, 'all.lock') >++ try: >++ st = os.stat(lockfile) >++ except EnvironmentError as e: >++ if e.errno == errno.ENOENT: >++ with open(lockfile, 'w') as f: >++ f.write('') >++ return >++ else: >++ raise >++ >++ if st.st_mtime < time.time() - EVICT_INTERVAL_MINUTES * 60: >++ # check every EVICT_INTERVAL_MINUTES minutes if the cache is too big >++ # OCLOEXEC is unnecessary because no processes are spawned >++ fd = os.open(lockfile, os.O_RDWR | os.O_CREAT, 0o755) >++ try: >++ try: >++ fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) >++ except EnvironmentError: >++ sys.stderr.write('another process is running!\n') >++ pass >++ else: >++ # now dow the actual cleanup >++ lru_trim() >++ os.utime(lockfile, None) >++ finally: >++ os.close(fd) >++ >++class netcache(object): >++ def __init__(self): >++ self.http = urllib3.PoolManager() >++ >++ def url_of(self, sig, i): >++ return "%s/%s/%s" % (CACHE_DIR, sig, i) >++ >++ def upload(self, file_path, sig, i): >++ url = self.url_of(sig, i) >++ with open(file_path, 'rb') as f: >++ file_data = f.read() >++ r = self.http.request('POST', url, timeout=60, >++ fields={ 'file': ('%s/%s' % (sig, i), file_data), }) >++ if r.status >= 400: >++ raise OSError("Invalid status %r %r" % (url, r.status)) >++ >++ def download(self, file_path, sig, i): >++ url = self.url_of(sig, i) >++ with self.http.request('GET', url, preload_content=False, timeout=60) as inf: >++ if inf.status >= 400: >++ raise OSError("Invalid status %r %r" % (url, inf.status)) >++ with open(file_path, 'wb') as out: >++ shutil.copyfileobj(inf, out) >++ >++ def copy_to_cache(self, sig, files_from, files_to): >++ try: >++ for i, x in enumerate(files_from): >++ if not os.path.islink(x): >++ self.upload(x, sig, i) >++ except Exception: >++ return traceback.format_exc() >++ return OK >++ >++ def copy_from_cache(self, sig, files_from, files_to): >++ try: >++ for i, x in enumerate(files_to): >++ self.download(x, sig, i) >++ except Exception: >++ return traceback.format_exc() >++ return OK >++ >++class fcache(object): >++ def __init__(self): >++ if not os.path.exists(CACHE_DIR): >++ os.makedirs(CACHE_DIR) >++ if not os.path.exists(CACHE_DIR): >++ raise ValueError('Could not initialize the cache directory') >++ >++ def copy_to_cache(self, sig, files_from, files_to): >++ """ >++ Copy files to the cache, existing files are overwritten, >++ and the copy is atomic only for a given file, not for all files >++ that belong to a given task object >++ """ >++ try: >++ for i, x in enumerate(files_from): >++ dest = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) >++ atomic_copy(x, dest) >++ except Exception: >++ return traceback.format_exc() >++ else: >++ # attempt trimming if caching was successful: >++ # we may have things to trim! >++ lru_evict() >++ return OK >++ >++ def copy_from_cache(self, sig, files_from, files_to): >++ """ >++ Copy files from the cache >++ """ >++ try: >++ for i, x in enumerate(files_to): >++ orig = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) >++ atomic_copy(orig, x) >++ >++ # success! update the cache time >++ os.utime(os.path.join(CACHE_DIR, sig[:2], sig), None) >++ except Exception: >++ return traceback.format_exc() >++ return OK >++ >++class bucket_cache(object): >++ def bucket_copy(self, source, target): >++ if CACHE_DIR.startswith('s3://'): >++ cmd = ['aws', 's3', 'cp', source, target] >++ else: >++ cmd = ['gsutil', 'cp', source, target] >++ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) >++ out, err = proc.communicate() >++ if proc.returncode: >++ raise OSError('Error copy %r to %r using: %r (exit %r):\n out:%s\n err:%s' % ( >++ source, target, cmd, proc.returncode, out.decode(), err.decode())) >++ >++ def copy_to_cache(self, sig, files_from, files_to): >++ try: >++ for i, x in enumerate(files_from): >++ dest = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) >++ self.bucket_copy(x, dest) >++ except Exception: >++ return traceback.format_exc() >++ return OK >++ >++ def copy_from_cache(self, sig, files_from, files_to): >++ try: >++ for i, x in enumerate(files_to): >++ orig = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) >++ self.bucket_copy(orig, x) >++ except EnvironmentError: >++ return traceback.format_exc() >++ return OK >++ >++def loop(service): >++ """ >++ This function is run when this file is run as a standalone python script, >++ it assumes a parent process that will communicate the commands to it >++ as pickled-encoded tuples (one line per command) >++ >++ The commands are to copy files to the cache or copy files from the >++ cache to a target destination >++ """ >++ # one operation is performed at a single time by a single process >++ # therefore stdin never has more than one line >++ txt = sys.stdin.readline().strip() >++ if not txt: >++ # parent process probably ended >++ sys.exit(1) >++ ret = OK >++ >++ [sig, files_from, files_to] = cPickle.loads(base64.b64decode(txt)) >++ if files_from: >++ # TODO return early when pushing files upstream >++ ret = service.copy_to_cache(sig, files_from, files_to) >++ elif files_to: >++ # the build process waits for workers to (possibly) obtain files from the cache >++ ret = service.copy_from_cache(sig, files_from, files_to) >++ else: >++ ret = "Invalid command" >++ >++ obj = base64.b64encode(cPickle.dumps(ret)) >++ sys.stdout.write(obj.decode()) >++ sys.stdout.write('\n') >++ sys.stdout.flush() >++ >++if __name__ == '__main__': >++ if CACHE_DIR.startswith('s3://') or CACHE_DIR.startswith('gs://'): >++ service = bucket_cache() >++ elif CACHE_DIR.startswith('http'): >++ service = netcache() >++ else: >++ service = fcache() >++ while 1: >++ try: >++ loop(service) >++ except KeyboardInterrupt: >++ break >++ >+-- >+2.37.3 >+ >diff --git a/net/samba413/files/patch-waf-2.0.21 b/net/samba413/files/patch-waf-2.0.21 >new file mode 100644 >index 000000000000..01b2d6e6cafe >--- /dev/null >+++ b/net/samba413/files/patch-waf-2.0.21 >@@ -0,0 +1,703 @@ >+From 6718b5e6d059e5668fc538be802ebd9fbe5ce9af Mon Sep 17 00:00:00 2001 >+From: Stefan Metzmacher <metze@samba.org> >+Date: Wed, 25 Nov 2020 16:29:06 +0100 >+Subject: [PATCH] waf: upgrade to 2.0.21 >+ >+This commit message was wrong: >+ >+ commit 5fc3a71d0f54b176d3cb2e399718d0468507e797 >+ Author: David Mulder <dmulder@suse.com> >+ Date: Mon Aug 24 13:12:46 2020 -0600 >+ >+ waf: upgrade to 2.0.20 >+ >+ This contain an important change: >+ "Fix gccdeps.scan() returning nodes that no longer exist on disk." >+ https://gitlab.com/ita1024/waf/-/merge_requests/2293 >+ >+ Signed-off-by: David Mulder <dmulder@suse.com> >+ Reviewed-by: Stefan Metzmacher <metze@samba.org> >+Reviewed-by: Andrew Bartlett <abartlet@samba.org> >+ >+The fix was in in waf master, but not included in 2.0.20, >+but it's now included in 2.0.21. >+ >+Signed-off-by: Stefan Metzmacher <metze@samba.org> >+Reviewed-by: Andrew Bartlett <abartlet@samba.org> >+--- >+ buildtools/bin/waf | 2 +- >+ buildtools/wafsamba/wafsamba.py | 2 +- >+ third_party/waf/waflib/Build.py | 6 ++- >+ third_party/waf/waflib/Context.py | 8 ++-- >+ third_party/waf/waflib/Tools/asm.py | 5 +- >+ third_party/waf/waflib/Tools/c_config.py | 1 + >+ third_party/waf/waflib/Tools/msvc.py | 8 +++- >+ third_party/waf/waflib/Tools/qt5.py | 26 +++++++++-- >+ third_party/waf/waflib/Tools/waf_unit_test.py | 10 +++- >+ third_party/waf/waflib/extras/boost.py | 5 +- >+ .../waf/waflib/extras/c_dumbpreproc.py | 2 +- >+ third_party/waf/waflib/extras/doxygen.py | 4 +- >+ .../waf/waflib/extras/file_to_object.py | 9 +++- >+ third_party/waf/waflib/extras/gccdeps.py | 21 +++++++-- >+ third_party/waf/waflib/extras/msvcdeps.py | 27 +++++++++-- >+ third_party/waf/waflib/extras/pch.py | 4 +- >+ third_party/waf/waflib/extras/sphinx.py | 40 ++++++++++++---- >+ third_party/waf/waflib/extras/wafcache.py | 46 +++++++++++++++---- >+ third_party/waf/waflib/extras/xcode6.py | 18 ++++---- >+ 19 files changed, 181 insertions(+), 63 deletions(-) >+ >+diff --git buildtools/bin/waf buildtools/bin/waf >+index feabe25d131..041450fc131 100755 >+--- buildtools/bin/waf >++++ buildtools/bin/waf >+@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. >+ >+ import os, sys, inspect >+ >+-VERSION="2.0.20" >++VERSION="2.0.21" >+ REVISION="x" >+ GIT="x" >+ INSTALL="x" >+diff --git buildtools/wafsamba/wafsamba.py buildtools/wafsamba/wafsamba.py >+index 9dd6d05b91b..d1baa3b4940 100644 >+--- buildtools/wafsamba/wafsamba.py >++++ buildtools/wafsamba/wafsamba.py >+@@ -38,7 +38,7 @@ LIB_PATH="shared" >+ >+ os.environ['PYTHONUNBUFFERED'] = '1' >+ >+-if Context.HEXVERSION not in (0x2001400,): >++if Context.HEXVERSION not in (0x2001500,): >+ Logs.error(''' >+ Please use the version of waf that comes with Samba, not >+ a system installed version. See http://wiki.samba.org/index.php/Waf >+diff --git third_party/waf/waflib/Build.py third_party/waf/waflib/Build.py >+index 39f0991918b..52837618577 100644 >+--- third_party/waf/waflib/Build.py >++++ third_party/waf/waflib/Build.py >+@@ -753,10 +753,12 @@ class BuildContext(Context.Context): >+ else: >+ ln = self.launch_node() >+ if ln.is_child_of(self.bldnode): >+- Logs.warn('Building from the build directory, forcing --targets=*') >++ if Logs.verbose > 1: >++ Logs.warn('Building from the build directory, forcing --targets=*') >+ ln = self.srcnode >+ elif not ln.is_child_of(self.srcnode): >+- Logs.warn('CWD %s is not under %s, forcing --targets=* (run distclean?)', ln.abspath(), self.srcnode.abspath()) >++ if Logs.verbose > 1: >++ Logs.warn('CWD %s is not under %s, forcing --targets=* (run distclean?)', ln.abspath(), self.srcnode.abspath()) >+ ln = self.srcnode >+ >+ def is_post(tg, ln): >+diff --git third_party/waf/waflib/Context.py third_party/waf/waflib/Context.py >+index 3f1b4fa48ab..0ce9df6e91f 100644 >+--- third_party/waf/waflib/Context.py >++++ third_party/waf/waflib/Context.py >+@@ -18,13 +18,13 @@ else: >+ import imp >+ >+ # the following 3 constants are updated on each new release (do not touch) >+-HEXVERSION=0x2001400 >++HEXVERSION=0x2001500 >+ """Constant updated on new releases""" >+ >+-WAFVERSION="2.0.20" >++WAFVERSION="2.0.21" >+ """Constant updated on new releases""" >+ >+-WAFREVISION="668769470956da8c5b60817cb8884cd7d0f87cd4" >++WAFREVISION="edde20a6425a5c3eb6b47d5f3f5c4fbc93fed5f4" >+ """Git revision when the waf version is updated""" >+ >+ WAFNAME="waf" >+@@ -530,7 +530,7 @@ class Context(ctx): >+ """ >+ Prints a configuration message of the form ``msg: result``. >+ The second part of the message will be in colors. The output >+- can be disabled easly by setting ``in_msg`` to a positive value:: >++ can be disabled easily by setting ``in_msg`` to a positive value:: >+ >+ def configure(conf): >+ self.in_msg = 1 >+diff --git third_party/waf/waflib/Tools/asm.py third_party/waf/waflib/Tools/asm.py >+index a57e83bb5ec..1d34ddaca7f 100644 >+--- third_party/waf/waflib/Tools/asm.py >++++ third_party/waf/waflib/Tools/asm.py >+@@ -56,13 +56,11 @@ class asm(Task.Task): >+ Compiles asm files by gas/nasm/yasm/... >+ """ >+ color = 'BLUE' >+- run_str = '${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}' >++ run_str = '${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${ASMDEFINES_ST:DEFINES} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}' >+ >+ def scan(self): >+ if self.env.ASM_NAME == 'gas': >+ return c_preproc.scan(self) >+- Logs.warn('There is no dependency scanner for Nasm!') >+- return [[], []] >+ elif self.env.ASM_NAME == 'nasm': >+ Logs.warn('The Nasm dependency scanner is incomplete!') >+ >+@@ -106,3 +104,4 @@ class asmstlib(stlink_task): >+ >+ def configure(conf): >+ conf.env.ASMPATH_ST = '-I%s' >++ conf.env.ASMDEFINES_ST = '-D%s' >+diff --git third_party/waf/waflib/Tools/c_config.py third_party/waf/waflib/Tools/c_config.py >+index 98187fac2e2..03b6bf61bc0 100644 >+--- third_party/waf/waflib/Tools/c_config.py >++++ third_party/waf/waflib/Tools/c_config.py >+@@ -68,6 +68,7 @@ MACRO_TO_DEST_CPU = { >+ '__s390__' : 's390', >+ '__sh__' : 'sh', >+ '__xtensa__' : 'xtensa', >++'__e2k__' : 'e2k', >+ } >+ >+ @conf >+diff --git third_party/waf/waflib/Tools/msvc.py third_party/waf/waflib/Tools/msvc.py >+index f169c7f441b..37233be8242 100644 >+--- third_party/waf/waflib/Tools/msvc.py >++++ third_party/waf/waflib/Tools/msvc.py >+@@ -99,7 +99,13 @@ all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), >+ """List of icl platforms""" >+ >+ def options(opt): >+- opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default='') >++ default_ver = '' >++ vsver = os.getenv('VSCMD_VER') >++ if vsver: >++ m = re.match(r'(^\d+\.\d+).*', vsver) >++ if m: >++ default_ver = 'msvc %s' % m.group(1) >++ opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default=default_ver) >+ opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='') >+ opt.add_option('--no-msvc-lazy', action='store_false', help = 'lazily check msvc target environments', default=True, dest='msvc_lazy') >+ >+diff --git third_party/waf/waflib/Tools/qt5.py third_party/waf/waflib/Tools/qt5.py >+index 99e021bae61..cff2028174f 100644 >+--- third_party/waf/waflib/Tools/qt5.py >++++ third_party/waf/waflib/Tools/qt5.py >+@@ -57,7 +57,23 @@ A few options (--qt{dir,bin,...}) and environment variables >+ (QT5_{ROOT,DIR,MOC,UIC,XCOMPILE}) allow finer tuning of the tool, >+ tool path selection, etc; please read the source for more info. >+ >+-The detection uses pkg-config on Linux by default. To force static library detection use: >++The detection uses pkg-config on Linux by default. The list of >++libraries to be requested to pkg-config is formulated by scanning >++in the QTLIBS directory (that can be passed via --qtlibs or by >++setting the environment variable QT5_LIBDIR otherwise is derived >++by querying qmake for QT_INSTALL_LIBS directory) for shared/static >++libraries present. >++Alternatively the list of libraries to be requested via pkg-config >++can be set using the qt5_vars attribute, ie: >++ >++ conf.qt5_vars = ['Qt5Core', 'Qt5Gui', 'Qt5Widgets', 'Qt5Test']; >++ >++This can speed up configuration phase if needed libraries are >++known beforehand, can improve detection on systems with a >++sparse QT5 libraries installation (ie. NIX) and can improve >++detection of some header-only Qt modules (ie. Qt5UiPlugin). >++ >++To force static library detection use: >+ QT5_XCOMPILE=1 QT5_FORCE_STATIC=1 waf configure >+ """ >+ >+@@ -466,6 +482,9 @@ def configure(self): >+ >+ The detection uses the program ``pkg-config`` through :py:func:`waflib.Tools.config_c.check_cfg` >+ """ >++ if 'COMPILER_CXX' not in self.env: >++ self.fatal('No CXX compiler defined: did you forget to configure compiler_cxx first?') >++ >+ self.find_qt5_binaries() >+ self.set_qt5_libs_dir() >+ self.set_qt5_libs_to_check() >+@@ -478,9 +497,6 @@ def configure(self): >+ if not has_xml: >+ Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!') >+ >+- if 'COMPILER_CXX' not in self.env: >+- self.fatal('No CXX compiler defined: did you forget to configure compiler_cxx first?') >+- >+ # Qt5 may be compiled with '-reduce-relocations' which requires dependent programs to have -fPIE or -fPIC? >+ frag = '#include <QMap>\nint main(int argc, char **argv) {QMap<int,int> m;return m.keys().size();}\n' >+ uses = 'QT5CORE' >+@@ -637,7 +653,7 @@ def set_qt5_libs_dir(self): >+ except Errors.WafError: >+ qtdir = self.cmd_and_log(env.QMAKE + ['-query', 'QT_INSTALL_PREFIX']).strip() >+ qtlibs = os.path.join(qtdir, 'lib') >+- self.msg('Found the Qt5 libraries in', qtlibs) >++ self.msg('Found the Qt5 library path', qtlibs) >+ env.QTLIBS = qtlibs >+ >+ @conf >+diff --git third_party/waf/waflib/Tools/waf_unit_test.py third_party/waf/waflib/Tools/waf_unit_test.py >+index 6ff6f72739f..dc66fe9c184 100644 >+--- third_party/waf/waflib/Tools/waf_unit_test.py >++++ third_party/waf/waflib/Tools/waf_unit_test.py >+@@ -97,6 +97,7 @@ def make_interpreted_test(self): >+ if isinstance(v, str): >+ v = v.split(os.pathsep) >+ self.ut_env[k] = os.pathsep.join(p + v) >++ self.env.append_value('UT_DEPS', ['%r%r' % (key, self.ut_env[key]) for key in self.ut_env]) >+ >+ @feature('test') >+ @after_method('apply_link', 'process_use') >+@@ -108,7 +109,8 @@ def make_test(self): >+ tsk = self.create_task('utest', self.link_task.outputs) >+ if getattr(self, 'ut_str', None): >+ self.ut_run, lst = Task.compile_fun(self.ut_str, shell=getattr(self, 'ut_shell', False)) >+- tsk.vars = lst + tsk.vars >++ tsk.vars = tsk.vars + lst >++ self.env.append_value('UT_DEPS', self.ut_str) >+ >+ self.handle_ut_cwd('ut_cwd') >+ >+@@ -139,6 +141,10 @@ def make_test(self): >+ if not hasattr(self, 'ut_cmd'): >+ self.ut_cmd = getattr(Options.options, 'testcmd', False) >+ >++ self.env.append_value('UT_DEPS', str(self.ut_cmd)) >++ self.env.append_value('UT_DEPS', self.ut_paths) >++ self.env.append_value('UT_DEPS', ['%r%r' % (key, self.ut_env[key]) for key in self.ut_env]) >++ >+ @taskgen_method >+ def add_test_results(self, tup): >+ """Override and return tup[1] to interrupt the build immediately if a test does not run""" >+@@ -159,7 +165,7 @@ class utest(Task.Task): >+ """ >+ color = 'PINK' >+ after = ['vnum', 'inst'] >+- vars = [] >++ vars = ['UT_DEPS'] >+ >+ def runnable_status(self): >+ """ >+diff --git third_party/waf/waflib/extras/boost.py third_party/waf/waflib/extras/boost.py >+index c2aaaa938a2..93b312a1e6e 100644 >+--- third_party/waf/waflib/extras/boost.py >++++ third_party/waf/waflib/extras/boost.py >+@@ -270,10 +270,12 @@ def boost_get_libs(self, *k, **kw): >+ return file >+ return None >+ >++ # extensions from Tools.ccroot.lib_patterns >++ wo_ext = re.compile(r"\.(a|so|lib|dll|dylib)(\.[0-9\.]+)?$") >+ def format_lib_name(name): >+ if name.startswith('lib') and self.env.CC_NAME != 'msvc': >+ name = name[3:] >+- return name[:name.rfind('.')] >++ return wo_ext.sub("", name) >+ >+ def match_libs(lib_names, is_static): >+ libs = [] >+@@ -522,4 +524,3 @@ def install_boost(self): >+ except: >+ continue >+ install_boost.done = False >+- >+diff --git third_party/waf/waflib/extras/c_dumbpreproc.py third_party/waf/waflib/extras/c_dumbpreproc.py >+index ce9e1a400b9..1fdd5c364ae 100644 >+--- third_party/waf/waflib/extras/c_dumbpreproc.py >++++ third_party/waf/waflib/extras/c_dumbpreproc.py >+@@ -66,7 +66,7 @@ class dumb_parser(parser): >+ if x == c_preproc.POPFILE: >+ self.currentnode_stack.pop() >+ continue >+- self.tryfind(y) >++ self.tryfind(y, env=env) >+ >+ c_preproc.c_parser = dumb_parser >+ >+diff --git third_party/waf/waflib/extras/doxygen.py third_party/waf/waflib/extras/doxygen.py >+index de75bc2738a..0fda70361f3 100644 >+--- third_party/waf/waflib/extras/doxygen.py >++++ third_party/waf/waflib/extras/doxygen.py >+@@ -208,10 +208,10 @@ def process_doxy(self): >+ self.bld.fatal('doxygen file %s not found' % self.doxyfile) >+ >+ # the task instance >+- dsk = self.create_task('doxygen', node) >++ dsk = self.create_task('doxygen', node, always_run=getattr(self, 'always', False)) >+ >+ if getattr(self, 'doxy_tar', None): >+- tsk = self.create_task('tar') >++ tsk = self.create_task('tar', always_run=getattr(self, 'always', False)) >+ tsk.input_tasks = [dsk] >+ tsk.set_outputs(self.path.find_or_declare(self.doxy_tar)) >+ if self.doxy_tar.endswith('bz2'): >+diff --git third_party/waf/waflib/extras/file_to_object.py third_party/waf/waflib/extras/file_to_object.py >+index 1393b511d63..13d2aef37df 100644 >+--- third_party/waf/waflib/extras/file_to_object.py >++++ third_party/waf/waflib/extras/file_to_object.py >+@@ -31,7 +31,7 @@ Known issues: >+ >+ """ >+ >+-import os >++import os, sys >+ from waflib import Task, TaskGen, Errors >+ >+ def filename_c_escape(x): >+@@ -95,12 +95,17 @@ class file_to_object_c(Task.Task): >+ >+ name = "_binary_" + "".join(name) >+ >++ def char_to_num(ch): >++ if sys.version_info[0] < 3: >++ return ord(ch) >++ return ch >++ >+ data = self.inputs[0].read('rb') >+ lines, line = [], [] >+ for idx_byte, byte in enumerate(data): >+ line.append(byte) >+ if len(line) > 15 or idx_byte == size-1: >+- lines.append(", ".join(("0x%02x" % ord(x)) for x in line)) >++ lines.append(", ".join(("0x%02x" % char_to_num(x)) for x in line)) >+ line = [] >+ data = ",\n ".join(lines) >+ >+diff --git third_party/waf/waflib/extras/gccdeps.py third_party/waf/waflib/extras/gccdeps.py >+index c3a809e252a..1fc9373489a 100644 >+--- third_party/waf/waflib/extras/gccdeps.py >++++ third_party/waf/waflib/extras/gccdeps.py >+@@ -163,10 +163,25 @@ def post_run(self): >+ def sig_implicit_deps(self): >+ if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: >+ return super(self.derived_gccdeps, self).sig_implicit_deps() >++ bld = self.generator.bld >++ >+ try: >+- return Task.Task.sig_implicit_deps(self) >+- except Errors.WafError: >+- return Utils.SIG_NIL >++ return self.compute_sig_implicit_deps() >++ except Errors.TaskNotReady: >++ raise ValueError("Please specify the build order precisely with gccdeps (asm/c/c++ tasks)") >++ except EnvironmentError: >++ # If a file is renamed, assume the dependencies are stale and must be recalculated >++ for x in bld.node_deps.get(self.uid(), []): >++ if not x.is_bld() and not x.exists(): >++ try: >++ del x.parent.children[x.name] >++ except KeyError: >++ pass >++ >++ key = self.uid() >++ bld.node_deps[key] = [] >++ bld.raw_deps[key] = [] >++ return Utils.SIG_NIL >+ >+ def wrap_compiled_task(classname): >+ derived_class = type(classname, (Task.classes[classname],), {}) >+diff --git third_party/waf/waflib/extras/msvcdeps.py third_party/waf/waflib/extras/msvcdeps.py >+index 873a4193150..52985dce058 100644 >+--- third_party/waf/waflib/extras/msvcdeps.py >++++ third_party/waf/waflib/extras/msvcdeps.py >+@@ -150,11 +150,25 @@ def scan(self): >+ def sig_implicit_deps(self): >+ if self.env.CC_NAME not in supported_compilers: >+ return super(self.derived_msvcdeps, self).sig_implicit_deps() >++ bld = self.generator.bld >+ >+ try: >+- return Task.Task.sig_implicit_deps(self) >+- except Errors.WafError: >+- return Utils.SIG_NIL >++ return self.compute_sig_implicit_deps() >++ except Errors.TaskNotReady: >++ raise ValueError("Please specify the build order precisely with msvcdeps (c/c++ tasks)") >++ except EnvironmentError: >++ # If a file is renamed, assume the dependencies are stale and must be recalculated >++ for x in bld.node_deps.get(self.uid(), []): >++ if not x.is_bld() and not x.exists(): >++ try: >++ del x.parent.children[x.name] >++ except KeyError: >++ pass >++ >++ key = self.uid() >++ bld.node_deps[key] = [] >++ bld.raw_deps[key] = [] >++ return Utils.SIG_NIL >+ >+ def exec_command(self, cmd, **kw): >+ if self.env.CC_NAME not in supported_compilers: >+@@ -211,11 +225,14 @@ def exec_command(self, cmd, **kw): >+ # get one from the exception object >+ ret = getattr(e, 'returncode', 1) >+ >++ Logs.debug('msvcdeps: Running for: %s' % self.inputs[0]) >+ for line in raw_out.splitlines(): >+ if line.startswith(INCLUDE_PATTERN): >+- inc_path = line[len(INCLUDE_PATTERN):].strip() >++ # Only strip whitespace after log to preserve >++ # dependency structure in debug output >++ inc_path = line[len(INCLUDE_PATTERN):] >+ Logs.debug('msvcdeps: Regex matched %s', inc_path) >+- self.msvcdeps_paths.append(inc_path) >++ self.msvcdeps_paths.append(inc_path.strip()) >+ else: >+ out.append(line) >+ >+diff --git third_party/waf/waflib/extras/pch.py third_party/waf/waflib/extras/pch.py >+index 103e752838c..b44c7a2e8fd 100644 >+--- third_party/waf/waflib/extras/pch.py >++++ third_party/waf/waflib/extras/pch.py >+@@ -90,7 +90,7 @@ def apply_pch(self): >+ >+ if getattr(self, 'name', None): >+ try: >+- task = self.bld.pch_tasks["%s.%s" % (self.name, self.idx)] >++ task = self.bld.pch_tasks[self.name] >+ self.bld.fatal("Duplicated 'pch' task with name %r" % "%s.%s" % (self.name, self.idx)) >+ except KeyError: >+ pass >+@@ -104,7 +104,7 @@ def apply_pch(self): >+ >+ self.pch_task = task >+ if getattr(self, 'name', None): >+- self.bld.pch_tasks["%s.%s" % (self.name, self.idx)] = task >++ self.bld.pch_tasks[self.name] = task >+ >+ @TaskGen.feature('cxx') >+ @TaskGen.after_method('process_source', 'propagate_uselib_vars') >+diff --git third_party/waf/waflib/extras/sphinx.py third_party/waf/waflib/extras/sphinx.py >+index ce11110e634..71d1028393b 100644 >+--- third_party/waf/waflib/extras/sphinx.py >++++ third_party/waf/waflib/extras/sphinx.py >+@@ -20,7 +20,7 @@ def build(bld): >+ >+ from waflib.Node import Node >+ from waflib import Utils >+-from waflib.Task import Task >++from waflib import Task >+ from waflib.TaskGen import feature, after_method >+ >+ >+@@ -55,13 +55,9 @@ def build_sphinx(self): >+ sphinx_build_task.set_outputs(self.path.get_bld()) >+ >+ # the sphinx-build results are in <build + output_format> directory >+- sphinx_output_directory = self.path.get_bld().make_node(self.env.SPHINX_OUTPUT_FORMAT) >+- sphinx_output_directory.mkdir() >++ self.sphinx_output_directory = self.path.get_bld().make_node(self.env.SPHINX_OUTPUT_FORMAT) >++ self.sphinx_output_directory.mkdir() >+ Utils.def_attrs(self, install_path=get_install_path(self)) >+- self.add_install_files(install_to=self.install_path, >+- install_from=sphinx_output_directory.ant_glob('**/*'), >+- cwd=sphinx_output_directory, >+- relative_trick=True) >+ >+ >+ def get_install_path(tg): >+@@ -73,9 +69,37 @@ def get_install_path(tg): >+ return tg.env.DOCDIR >+ >+ >+-class SphinxBuildingTask(Task): >++class SphinxBuildingTask(Task.Task): >+ color = 'BOLD' >+ run_str = '${SPHINX_BUILD} -M ${SPHINX_OUTPUT_FORMAT} ${SRC} ${TGT} ${SPHINX_OPTIONS}' >+ >+ def keyword(self): >+ return 'Compiling (%s)' % self.env.SPHINX_OUTPUT_FORMAT >++ >++ def runnable_status(self): >++ >++ for x in self.run_after: >++ if not x.hasrun: >++ return Task.ASK_LATER >++ >++ self.signature() >++ ret = Task.Task.runnable_status(self) >++ if ret == Task.SKIP_ME: >++ # in case the files were removed >++ self.add_install() >++ return ret >++ >++ >++ def post_run(self): >++ self.add_install() >++ return Task.Task.post_run(self) >++ >++ >++ def add_install(self): >++ nodes = self.generator.sphinx_output_directory.ant_glob('**/*', quiet=True) >++ self.outputs += nodes >++ self.generator.add_install_files(install_to=self.generator.install_path, >++ install_from=nodes, >++ postpone=False, >++ cwd=self.generator.sphinx_output_directory, >++ relative_trick=True) >+diff --git third_party/waf/waflib/extras/wafcache.py third_party/waf/waflib/extras/wafcache.py >+index 8b9567faf14..088fd0d098d 100644 >+--- third_party/waf/waflib/extras/wafcache.py >++++ third_party/waf/waflib/extras/wafcache.py >+@@ -16,10 +16,19 @@ The following environment variables may be set: >+ - URL to a cache server, for example: >+ export WAFCACHE=http://localhost:8080/files/ >+ in that case, GET/POST requests are made to urls of the form >+- http://localhost:8080/files/000000000/0 (cache management is then up to the server) >+- - GCS or S3 bucket >+- gs://my-bucket/ >+- s3://my-bucket/ >++ http://localhost:8080/files/000000000/0 (cache management is delegated to the server) >++ - GCS, S3 or MINIO bucket >++ gs://my-bucket/ (uses gsutil command line tool or WAFCACHE_CMD) >++ s3://my-bucket/ (uses aws command line tool or WAFCACHE_CMD) >++ minio://my-bucket/ (uses mc command line tool or WAFCACHE_CMD) >++* WAFCACHE_CMD: bucket upload/download command, for example: >++ WAFCACHE_CMD="gsutil cp %{SRC} %{TGT}" >++ Note that the WAFCACHE bucket value is used for the source or destination >++ depending on the operation (upload or download). For example, with: >++ WAFCACHE="gs://mybucket/" >++ the following commands may be run: >++ gsutil cp build/myprogram gs://mybucket/aa/aaaaa/1 >++ gsutil cp gs://mybucket/bb/bbbbb/2 build/somefile >+ * WAFCACHE_NO_PUSH: if set, disables pushing to the cache >+ * WAFCACHE_VERBOSITY: if set, displays more detailed cache operations >+ >+@@ -30,6 +39,7 @@ File cache specific options: >+ * WAFCACHE_EVICT_MAX_BYTES: maximum amount of cache size in bytes (10GB) >+ * WAFCACHE_EVICT_INTERVAL_MINUTES: minimum time interval to try >+ and trim the cache (3 minutess) >++ >+ Usage:: >+ >+ def build(bld): >+@@ -41,7 +51,7 @@ To troubleshoot:: >+ waf clean build --zones=wafcache >+ """ >+ >+-import atexit, base64, errno, fcntl, getpass, os, shutil, sys, time, traceback, urllib3 >++import atexit, base64, errno, fcntl, getpass, os, re, shutil, sys, time, traceback, urllib3, shlex >+ try: >+ import subprocess32 as subprocess >+ except ImportError: >+@@ -53,6 +63,7 @@ if not os.path.isdir(base_cache): >+ default_wafcache_dir = os.path.join(base_cache, 'wafcache_' + getpass.getuser()) >+ >+ CACHE_DIR = os.environ.get('WAFCACHE', default_wafcache_dir) >++WAFCACHE_CMD = os.environ.get('WAFCACHE_CMD') >+ TRIM_MAX_FOLDERS = int(os.environ.get('WAFCACHE_TRIM_MAX_FOLDER', 1000000)) >+ EVICT_INTERVAL_MINUTES = int(os.environ.get('WAFCACHE_EVICT_INTERVAL_MINUTES', 3)) >+ EVICT_MAX_BYTES = int(os.environ.get('WAFCACHE_EVICT_MAX_BYTES', 10**10)) >+@@ -60,6 +71,8 @@ WAFCACHE_NO_PUSH = 1 if os.environ.get('WAFCACHE_NO_PUSH') else 0 >+ WAFCACHE_VERBOSITY = 1 if os.environ.get('WAFCACHE_VERBOSITY') else 0 >+ OK = "ok" >+ >++re_waf_cmd = re.compile('(?P<src>%{SRC})|(?P<tgt>%{TGT})') >++ >+ try: >+ import cPickle >+ except ImportError: >+@@ -233,8 +246,9 @@ def build(bld): >+ # already called once >+ return >+ >+- for x in range(bld.jobs): >+- process_pool.append(get_process()) >++ # pre-allocation >++ processes = [get_process() for x in range(bld.jobs)] >++ process_pool.extend(processes) >+ >+ Task.Task.can_retrieve_cache = can_retrieve_cache >+ Task.Task.put_files_cache = put_files_cache >+@@ -449,10 +463,20 @@ class fcache(object): >+ >+ class bucket_cache(object): >+ def bucket_copy(self, source, target): >+- if CACHE_DIR.startswith('s3://'): >++ if WAFCACHE_CMD: >++ def replacer(match): >++ if match.group('src'): >++ return source >++ elif match.group('tgt'): >++ return target >++ cmd = [re_waf_cmd.sub(replacer, x) for x in shlex.split(WAFCACHE_CMD)] >++ elif CACHE_DIR.startswith('s3://'): >+ cmd = ['aws', 's3', 'cp', source, target] >+- else: >++ elif CACHE_DIR.startswith('gs://'): >+ cmd = ['gsutil', 'cp', source, target] >++ else: >++ cmd = ['mc', 'cp', source, target] >++ >+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) >+ out, err = proc.communicate() >+ if proc.returncode: >+@@ -510,7 +534,9 @@ def loop(service): >+ sys.stdout.flush() >+ >+ if __name__ == '__main__': >+- if CACHE_DIR.startswith('s3://') or CACHE_DIR.startswith('gs://'): >++ if CACHE_DIR.startswith('s3://') or CACHE_DIR.startswith('gs://') or CACHE_DIR.startswith('minio://'): >++ if CACHE_DIR.startswith('minio://'): >++ CACHE_DIR = CACHE_DIR[8:] # minio doesn't need the protocol part, uses config aliases >+ service = bucket_cache() >+ elif CACHE_DIR.startswith('http'): >+ service = netcache() >+diff --git third_party/waf/waflib/extras/xcode6.py third_party/waf/waflib/extras/xcode6.py >+index 91bbff181ec..c5b309120c9 100644 >+--- third_party/waf/waflib/extras/xcode6.py >++++ third_party/waf/waflib/extras/xcode6.py >+@@ -99,7 +99,7 @@ env.PROJ_CONFIGURATION = { >+ ... >+ } >+ 'Release': { >+- 'ARCHS' x86_64' >++ 'ARCHS': x86_64' >+ ... >+ } >+ } >+@@ -163,12 +163,12 @@ class XCodeNode(object): >+ result = result + "\t\t}" >+ return result >+ elif isinstance(value, str): >+- return "\"%s\"" % value >++ return '"%s"' % value.replace('"', '\\\\\\"') >+ elif isinstance(value, list): >+ result = "(\n" >+ for i in value: >+- result = result + "\t\t\t%s,\n" % self.tostring(i) >+- result = result + "\t\t)" >++ result = result + "\t\t\t\t%s,\n" % self.tostring(i) >++ result = result + "\t\t\t)" >+ return result >+ elif isinstance(value, XCodeNode): >+ return value._id >+@@ -565,13 +565,13 @@ def process_xcode(self): >+ # Override target specific build settings >+ bldsettings = { >+ 'HEADER_SEARCH_PATHS': ['$(inherited)'] + self.env['INCPATHS'], >+- 'LIBRARY_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.LIBPATH) + Utils.to_list(self.env.STLIBPATH) + Utils.to_list(self.env.LIBDIR) , >++ 'LIBRARY_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.LIBPATH) + Utils.to_list(self.env.STLIBPATH) + Utils.to_list(self.env.LIBDIR), >+ 'FRAMEWORK_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.FRAMEWORKPATH), >+- 'OTHER_LDFLAGS': libs + ' ' + frameworks, >+- 'OTHER_LIBTOOLFLAGS': bld.env['LINKFLAGS'], >++ 'OTHER_LDFLAGS': libs + ' ' + frameworks + ' ' + ' '.join(bld.env['LINKFLAGS']), >+ 'OTHER_CPLUSPLUSFLAGS': Utils.to_list(self.env['CXXFLAGS']), >+ 'OTHER_CFLAGS': Utils.to_list(self.env['CFLAGS']), >+- 'INSTALL_PATH': [] >++ 'INSTALL_PATH': [], >++ 'GCC_PREPROCESSOR_DEFINITIONS': self.env['DEFINES'] >+ } >+ >+ # Install path >+@@ -591,7 +591,7 @@ def process_xcode(self): >+ >+ # The keys represents different build configuration, e.g. Debug, Release and so on.. >+ # Insert our generated build settings to all configuration names >+- keys = set(settings.keys() + bld.env.PROJ_CONFIGURATION.keys()) >++ keys = set(settings.keys()) | set(bld.env.PROJ_CONFIGURATION.keys()) >+ for k in keys: >+ if k in settings: >+ settings[k].update(bldsettings) >+-- >+2.37.3 >+ >diff --git a/net/samba413/files/patch-waf-2.0.22 b/net/samba413/files/patch-waf-2.0.22 >new file mode 100644 >index 000000000000..db3c8edff8d3 >--- /dev/null >+++ b/net/samba413/files/patch-waf-2.0.22 >@@ -0,0 +1,596 @@ >+From 59ed09928541d40df72592419247add608a54aca Mon Sep 17 00:00:00 2001 >+From: Andreas Schneider <asn@samba.org> >+Date: Wed, 25 Aug 2021 15:34:58 +0200 >+Subject: [PATCH] third_party: Update waf to version 2.0.22 >+ >+New in waf 2.0.22 >+ >+* Fix stdin propagation with faulty vcvarsall scripts #2315 >+* Enable mixing Unix-style paths with destdir on Windows platforms #2337 >+* Fix shell escaping unit test parameters #2314 >+* Improve extras/clang_compilation_database and extras/swig compatibility #2336 >+* Propagate C++ flags to the Cuda compiler in extras/cuda #2311 >+* Fix detection of Qt 5.0.0 (preparation for Qt6) #2331 >+* Enable Haxe processing #2308 >+* Fix regression in MACOSX_DEPLOYMENT_TARGET caused by distutils #2330 >+* Fix extras/wafcache concurrent trimming issues #2312 >+* Fix extras/wafcache symlink handling #2327 >+ >+The import was done like this: >+ >+./third_party/waf/update.sh >+ >+Then changing buildtools/bin/waf and buildtools/wafsamba/wafsamba.py >+by hand. >+ >+Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> >+ >+Signed-off-by: Andreas Schneider <asn@samba.org> >+Signed-off-by: Stefan Metzmacher <metze@samba.org> >+Reviewed-by: Andrew Bartlett <abartlet@samba.org> >+ >+Autobuild-User(master): Andrew Bartlett <abartlet@samba.org> >+Autobuild-Date(master): Thu Sep 2 21:22:17 UTC 2021 on sn-devel-184 >+--- >+ buildtools/bin/waf | 2 +- >+ buildtools/wafsamba/wafsamba.py | 2 +- >+ third_party/waf/waflib/Build.py | 4 +- >+ third_party/waf/waflib/Context.py | 6 +- >+ third_party/waf/waflib/Tools/msvc.py | 2 +- >+ third_party/waf/waflib/Tools/python.py | 2 +- >+ third_party/waf/waflib/Tools/qt5.py | 6 +- >+ third_party/waf/waflib/Tools/waf_unit_test.py | 2 +- >+ third_party/waf/waflib/Utils.py | 15 +- >+ .../extras/clang_compilation_database.py | 28 ++-- >+ third_party/waf/waflib/extras/haxe.py | 131 ++++++++++++++++++ >+ third_party/waf/waflib/extras/wafcache.py | 59 ++++++-- >+ 12 files changed, 215 insertions(+), 44 deletions(-) >+ create mode 100644 third_party/waf/waflib/extras/haxe.py >+ >+diff --git buildtools/bin/waf buildtools/bin/waf >+index 041450fc131..b0ccb09a877 100755 >+--- buildtools/bin/waf >++++ buildtools/bin/waf >+@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. >+ >+ import os, sys, inspect >+ >+-VERSION="2.0.21" >++VERSION="2.0.22" >+ REVISION="x" >+ GIT="x" >+ INSTALL="x" >+diff --git buildtools/wafsamba/wafsamba.py buildtools/wafsamba/wafsamba.py >+index 4fe9daf160e..dee007bf84e 100644 >+--- buildtools/wafsamba/wafsamba.py >++++ buildtools/wafsamba/wafsamba.py >+@@ -38,7 +38,7 @@ LIB_PATH="shared" >+ >+ os.environ['PYTHONUNBUFFERED'] = '1' >+ >+-if Context.HEXVERSION not in (0x2001500,): >++if Context.HEXVERSION not in (0x2001600,): >+ Logs.error(''' >+ Please use the version of waf that comes with Samba, not >+ a system installed version. See http://wiki.samba.org/index.php/Waf >+diff --git third_party/waf/waflib/Build.py third_party/waf/waflib/Build.py >+index 52837618577..b49dd8302b1 100644 >+--- third_party/waf/waflib/Build.py >++++ third_party/waf/waflib/Build.py >+@@ -1066,9 +1066,9 @@ class inst(Task.Task): >+ else: >+ dest = os.path.normpath(Utils.subst_vars(self.install_to, self.env)) >+ if not os.path.isabs(dest): >+- dest = os.path.join(self.env.PREFIX, dest) >++ dest = os.path.join(self.env.PREFIX, dest) >+ if destdir and Options.options.destdir: >+- dest = os.path.join(Options.options.destdir, os.path.splitdrive(dest)[1].lstrip(os.sep)) >++ dest = Options.options.destdir.rstrip(os.sep) + os.sep + os.path.splitdrive(dest)[1].lstrip(os.sep) >+ return dest >+ >+ def copy_fun(self, src, tgt): >+diff --git third_party/waf/waflib/Context.py third_party/waf/waflib/Context.py >+index 0ce9df6e91f..07ee1201f03 100644 >+--- third_party/waf/waflib/Context.py >++++ third_party/waf/waflib/Context.py >+@@ -18,13 +18,13 @@ else: >+ import imp >+ >+ # the following 3 constants are updated on each new release (do not touch) >+-HEXVERSION=0x2001500 >++HEXVERSION=0x2001600 >+ """Constant updated on new releases""" >+ >+-WAFVERSION="2.0.21" >++WAFVERSION="2.0.22" >+ """Constant updated on new releases""" >+ >+-WAFREVISION="edde20a6425a5c3eb6b47d5f3f5c4fbc93fed5f4" >++WAFREVISION="816d5bc48ba2abc4ac22f2b44d94d322bf992b9c" >+ """Git revision when the waf version is updated""" >+ >+ WAFNAME="waf" >+diff --git third_party/waf/waflib/Tools/msvc.py third_party/waf/waflib/Tools/msvc.py >+index 37233be8242..0c4703aaee9 100644 >+--- third_party/waf/waflib/Tools/msvc.py >++++ third_party/waf/waflib/Tools/msvc.py >+@@ -193,7 +193,7 @@ echo PATH=%%PATH%% >+ echo INCLUDE=%%INCLUDE%% >+ echo LIB=%%LIB%%;%%LIBPATH%% >+ """ % (vcvars,target)) >+- sout = conf.cmd_and_log(['cmd.exe', '/E:on', '/V:on', '/C', batfile.abspath()]) >++ sout = conf.cmd_and_log(['cmd.exe', '/E:on', '/V:on', '/C', batfile.abspath()], stdin=getattr(Utils.subprocess, 'DEVNULL', None)) >+ lines = sout.splitlines() >+ >+ if not lines[0]: >+diff --git third_party/waf/waflib/Tools/python.py third_party/waf/waflib/Tools/python.py >+index b1c8dd01285..07442561dff 100644 >+--- third_party/waf/waflib/Tools/python.py >++++ third_party/waf/waflib/Tools/python.py >+@@ -327,7 +327,7 @@ def check_python_headers(conf, features='pyembed pyext'): >+ dct = dict(zip(v, lst)) >+ x = 'MACOSX_DEPLOYMENT_TARGET' >+ if dct[x]: >+- env[x] = conf.environ[x] = dct[x] >++ env[x] = conf.environ[x] = str(dct[x]) >+ env.pyext_PATTERN = '%s' + dct['SO'] # not a mistake >+ >+ >+diff --git third_party/waf/waflib/Tools/qt5.py third_party/waf/waflib/Tools/qt5.py >+index cff2028174f..82c83e18c8a 100644 >+--- third_party/waf/waflib/Tools/qt5.py >++++ third_party/waf/waflib/Tools/qt5.py >+@@ -566,7 +566,7 @@ def find_qt5_binaries(self): >+ # at the end, try to find qmake in the paths given >+ # keep the one with the highest version >+ cand = None >+- prev_ver = ['5', '0', '0'] >++ prev_ver = ['0', '0', '0'] >+ for qmk in ('qmake-qt5', 'qmake5', 'qmake'): >+ try: >+ qmake = self.find_program(qmk, path_list=paths) >+@@ -580,7 +580,7 @@ def find_qt5_binaries(self): >+ else: >+ if version: >+ new_ver = version.split('.') >+- if new_ver > prev_ver: >++ if new_ver[0] == '5' and new_ver > prev_ver: >+ cand = qmake >+ prev_ver = new_ver >+ >+@@ -783,7 +783,7 @@ def set_qt5_libs_to_check(self): >+ pat = self.env.cxxstlib_PATTERN >+ if Utils.unversioned_sys_platform() == 'darwin': >+ pat = r"%s\.framework" >+- re_qt = re.compile(pat%'Qt5?(?P<name>.*)'+'$') >++ re_qt = re.compile(pat % 'Qt5?(?P<name>\\D+)' + '$') >+ for x in dirlst: >+ m = re_qt.match(x) >+ if m: >+diff --git third_party/waf/waflib/Tools/waf_unit_test.py third_party/waf/waflib/Tools/waf_unit_test.py >+index dc66fe9c184..8cff89bdeb9 100644 >+--- third_party/waf/waflib/Tools/waf_unit_test.py >++++ third_party/waf/waflib/Tools/waf_unit_test.py >+@@ -206,7 +206,7 @@ class utest(Task.Task): >+ self.ut_exec = getattr(self.generator, 'ut_exec', [self.inputs[0].abspath()]) >+ ut_cmd = getattr(self.generator, 'ut_cmd', False) >+ if ut_cmd: >+- self.ut_exec = shlex.split(ut_cmd % ' '.join(self.ut_exec)) >++ self.ut_exec = shlex.split(ut_cmd % Utils.shell_escape(self.ut_exec)) >+ >+ return self.exec_command(self.ut_exec) >+ >+diff --git third_party/waf/waflib/Utils.py third_party/waf/waflib/Utils.py >+index fc64fa05154..669490ca908 100644 >+--- third_party/waf/waflib/Utils.py >++++ third_party/waf/waflib/Utils.py >+@@ -11,7 +11,7 @@ through Python versions 2.5 to 3.X and across different platforms (win32, linux, >+ >+ from __future__ import with_statement >+ >+-import atexit, os, sys, errno, inspect, re, datetime, platform, base64, signal, functools, time >++import atexit, os, sys, errno, inspect, re, datetime, platform, base64, signal, functools, time, shlex >+ >+ try: >+ import cPickle >+@@ -577,10 +577,13 @@ def quote_define_name(s): >+ fu = fu.upper() >+ return fu >+ >+-re_sh = re.compile('\\s|\'|"') >+-""" >+-Regexp used for shell_escape below >+-""" >++# shlex.quote didn't exist until python 3.3. Prior to that it was a non-documented >++# function in pipes. >++try: >++ shell_quote = shlex.quote >++except AttributeError: >++ import pipes >++ shell_quote = pipes.quote >+ >+ def shell_escape(cmd): >+ """ >+@@ -589,7 +592,7 @@ def shell_escape(cmd): >+ """ >+ if isinstance(cmd, str): >+ return cmd >+- return ' '.join(repr(x) if re_sh.search(x) else x for x in cmd) >++ return ' '.join(shell_quote(x) for x in cmd) >+ >+ def h_list(lst): >+ """ >+diff --git third_party/waf/waflib/extras/clang_compilation_database.py third_party/waf/waflib/extras/clang_compilation_database.py >+index ff71f22ecfd..17f66949376 100644 >+--- third_party/waf/waflib/extras/clang_compilation_database.py >++++ third_party/waf/waflib/extras/clang_compilation_database.py >+@@ -29,22 +29,9 @@ from waflib import Logs, TaskGen, Task, Build, Scripting >+ >+ Task.Task.keep_last_cmd = True >+ >+-@TaskGen.feature('c', 'cxx') >+-@TaskGen.after_method('process_use') >+-def collect_compilation_db_tasks(self): >+- "Add a compilation database entry for compiled tasks" >+- if not isinstance(self.bld, ClangDbContext): >+- return >+- >+- tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y) >+- for task in getattr(self, 'compiled_tasks', []): >+- if isinstance(task, tup): >+- self.bld.clang_compilation_database_tasks.append(task) >+- >+ class ClangDbContext(Build.BuildContext): >+ '''generates compile_commands.json by request''' >+ cmd = 'clangdb' >+- clang_compilation_database_tasks = [] >+ >+ def write_compilation_database(self): >+ """ >+@@ -78,6 +65,8 @@ class ClangDbContext(Build.BuildContext): >+ Build dry run >+ """ >+ self.restore() >++ self.cur_tasks = [] >++ self.clang_compilation_database_tasks = [] >+ >+ if not self.all_envs: >+ self.load_envs() >+@@ -103,8 +92,21 @@ class ClangDbContext(Build.BuildContext): >+ lst = [tg] >+ else: lst = tg.tasks >+ for tsk in lst: >++ if tsk.__class__.__name__ == "swig": >++ tsk.runnable_status() >++ if hasattr(tsk, 'more_tasks'): >++ lst.extend(tsk.more_tasks) >++ # Not all dynamic tasks can be processed, in some cases >++ # one may have to call the method "run()" like this: >++ #elif tsk.__class__.__name__ == 'src2c': >++ # tsk.run() >++ # if hasattr(tsk, 'more_tasks'): >++ # lst.extend(tsk.more_tasks) >++ >+ tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y) >+ if isinstance(tsk, tup): >++ self.clang_compilation_database_tasks.append(tsk) >++ tsk.nocache = True >+ old_exec = tsk.exec_command >+ tsk.exec_command = exec_command >+ tsk.run() >+diff --git third_party/waf/waflib/extras/haxe.py third_party/waf/waflib/extras/haxe.py >+new file mode 100644 >+index 00000000000..cb3ba6a949c >+--- /dev/null >++++ third_party/waf/waflib/extras/haxe.py >+@@ -0,0 +1,131 @@ >++import os, re >++from waflib import Utils, Task, Errors >++from waflib.TaskGen import extension, taskgen_method, feature >++from waflib.Configure import conf >++ >++@conf >++def libname_haxe(self, libname): >++ return libname >++ >++@conf >++def check_lib_haxe(self, libname, uselib_store=None): >++ haxe_libs = [node.name for node in self.root.find_node('haxe_libraries').ant_glob()] >++ changed = False >++ self.start_msg('Checking for library %s' % libname) >++ if libname + '.hxml' in haxe_libs: >++ self.end_msg('yes') >++ else: >++ changed = True >++ try: >++ cmd = self.env.LIX + ['+lib', libname] >++ res = self.cmd_and_log(cmd) >++ if (res): >++ raise Errors.WafError(res) >++ else: >++ self.end_msg('downloaded', color = 'YELLOW') >++ except Errors.WafError as e: >++ self.end_msg('no', color = 'RED') >++ self.fatal('Getting %s has failed' % libname) >++ >++ postfix = uselib_store if uselib_store else libname.upper() >++ self.env['LIB_' + postfix] += [self.libname_haxe(libname)] >++ return changed >++ >++@conf >++def check_libs_haxe(self, libnames, uselib_store=None): >++ changed = False >++ for libname in Utils.to_list(libnames): >++ if self.check_lib_haxe(libname, uselib_store): >++ changed = True >++ return changed >++ >++@conf >++def ensure_lix_pkg(self, *k, **kw): >++ if kw.get('compiler') == 'hx': >++ if isinstance(kw.get('libs'), list) and len(kw.get('libs')): >++ changed = self.check_libs_haxe(kw.get('libs'), kw.get('uselib_store')) >++ if changed: >++ try: >++ cmd = self.env.LIX + ['download'] >++ res = self.cmd_and_log(cmd) >++ if (res): >++ raise Errors.WafError(res) >++ except Errors.WafError as e: >++ self.fatal('lix download has failed') >++ else: >++ self.check_lib_haxe(kw.get('lib'), kw.get('uselib_store')) >++ >++@conf >++def haxe(bld, *k, **kw): >++ task_gen = bld(*k, **kw) >++ >++class haxe(Task.Task): >++ vars = ['HAXE', 'HAXE_VERSION', 'HAXEFLAGS'] >++ ext_out = ['.hl', '.c', '.h'] >++ >++ def run(self): >++ cmd = self.env.HAXE + self.env.HAXEFLAGS >++ return self.exec_command(cmd, stdout = open(os.devnull, 'w')) >++ >++@taskgen_method >++def init_haxe_task(self, node): >++ def addflags(flags): >++ self.env.append_value('HAXEFLAGS', flags) >++ >++ if node.suffix() == '.hxml': >++ addflags(self.path.abspath() + '/' + node.name) >++ else: >++ addflags(['-main', node.name]) >++ addflags(['-hl', self.path.get_bld().make_node(self.target).abspath()]) >++ addflags(['-cp', self.path.abspath()]) >++ addflags(['-D', 'resourcesPath=%s' % getattr(self, 'res', '')]) >++ if hasattr(self, 'use'): >++ for dep in self.use: >++ if self.env['LIB_' + dep]: >++ for lib in self.env['LIB_' + dep]: addflags(['-lib', lib]) >++ >++@extension('.hx', '.hxml') >++def haxe_file(self, node): >++ if len(self.source) > 1: >++ self.bld.fatal('Use separate task generators for multiple files') >++ >++ try: >++ haxetask = self.haxetask >++ except AttributeError: >++ haxetask = self.haxetask = self.create_task('haxe') >++ self.init_haxe_task(node) >++ >++ haxetask.inputs.append(node) >++ haxetask.outputs.append(self.path.get_bld().make_node(self.target)) >++ >++@conf >++def find_haxe(self, min_version): >++ npx = self.env.NPX = self.find_program('npx') >++ self.env.LIX = npx + ['lix'] >++ npx_haxe = self.env.HAXE = npx + ['haxe'] >++ try: >++ output = self.cmd_and_log(npx_haxe + ['-version']) >++ except Errors.WafError: >++ haxe_version = None >++ else: >++ ver = re.search(r'\d+.\d+.\d+', output).group().split('.') >++ haxe_version = tuple([int(x) for x in ver]) >++ >++ self.msg('Checking for haxe version', >++ haxe_version, haxe_version and haxe_version >= min_version) >++ if npx_haxe and haxe_version < min_version: >++ self.fatal('haxe version %r is too old, need >= %r' % (haxe_version, min_version)) >++ >++ self.env.HAXE_VERSION = haxe_version >++ return npx_haxe >++ >++@conf >++def check_haxe(self, min_version=(4,1,4)): >++ if self.env.HAXE_MINVER: >++ min_version = self.env.HAXE_MINVER >++ find_haxe(self, min_version) >++ >++def configure(self): >++ self.env.HAXEFLAGS = [] >++ self.check_haxe() >++ self.add_os_flags('HAXEFLAGS', dup = False) >+diff --git third_party/waf/waflib/extras/wafcache.py third_party/waf/waflib/extras/wafcache.py >+index 088fd0d098d..cc23fcd6673 100644 >+--- third_party/waf/waflib/extras/wafcache.py >++++ third_party/waf/waflib/extras/wafcache.py >+@@ -31,6 +31,7 @@ The following environment variables may be set: >+ gsutil cp gs://mybucket/bb/bbbbb/2 build/somefile >+ * WAFCACHE_NO_PUSH: if set, disables pushing to the cache >+ * WAFCACHE_VERBOSITY: if set, displays more detailed cache operations >++* WAFCACHE_STATS: if set, displays cache usage statistics on exit >+ >+ File cache specific options: >+ Files are copied using hard links by default; if the cache is located >+@@ -69,6 +70,7 @@ EVICT_INTERVAL_MINUTES = int(os.environ.get('WAFCACHE_EVICT_INTERVAL_MINUTES', 3 >+ EVICT_MAX_BYTES = int(os.environ.get('WAFCACHE_EVICT_MAX_BYTES', 10**10)) >+ WAFCACHE_NO_PUSH = 1 if os.environ.get('WAFCACHE_NO_PUSH') else 0 >+ WAFCACHE_VERBOSITY = 1 if os.environ.get('WAFCACHE_VERBOSITY') else 0 >++WAFCACHE_STATS = 1 if os.environ.get('WAFCACHE_STATS') else 0 >+ OK = "ok" >+ >+ re_waf_cmd = re.compile('(?P<src>%{SRC})|(?P<tgt>%{TGT})') >+@@ -93,6 +95,9 @@ def can_retrieve_cache(self): >+ sig = self.signature() >+ ssig = Utils.to_hex(self.uid() + sig) >+ >++ if WAFCACHE_STATS: >++ self.generator.bld.cache_reqs += 1 >++ >+ files_to = [node.abspath() for node in self.outputs] >+ err = cache_command(ssig, [], files_to) >+ if err.startswith(OK): >+@@ -100,6 +105,8 @@ def can_retrieve_cache(self): >+ Logs.pprint('CYAN', ' Fetched %r from cache' % files_to) >+ else: >+ Logs.debug('wafcache: fetched %r from cache', files_to) >++ if WAFCACHE_STATS: >++ self.generator.bld.cache_hits += 1 >+ else: >+ if WAFCACHE_VERBOSITY: >+ Logs.pprint('YELLOW', ' No cache entry %s' % files_to) >+@@ -117,11 +124,17 @@ def put_files_cache(self): >+ if WAFCACHE_NO_PUSH or getattr(self, 'cached', None) or not self.outputs: >+ return >+ >++ files_from = [] >++ for node in self.outputs: >++ path = node.abspath() >++ if not os.path.isfile(path): >++ return >++ files_from.append(path) >++ >+ bld = self.generator.bld >+ sig = self.signature() >+ ssig = Utils.to_hex(self.uid() + sig) >+ >+- files_from = [node.abspath() for node in self.outputs] >+ err = cache_command(ssig, files_from, []) >+ >+ if err.startswith(OK): >+@@ -129,6 +142,8 @@ def put_files_cache(self): >+ Logs.pprint('CYAN', ' Successfully uploaded %s to cache' % files_from) >+ else: >+ Logs.debug('wafcache: Successfully uploaded %r to cache', files_from) >++ if WAFCACHE_STATS: >++ self.generator.bld.cache_puts += 1 >+ else: >+ if WAFCACHE_VERBOSITY: >+ Logs.pprint('RED', ' Error caching step results %s: %s' % (files_from, err)) >+@@ -193,6 +208,10 @@ def make_cached(cls): >+ if getattr(cls, 'nocache', None) or getattr(cls, 'has_cache', False): >+ return >+ >++ full_name = "%s.%s" % (cls.__module__, cls.__name__) >++ if full_name in ('waflib.Tools.ccroot.vnum', 'waflib.Build.inst'): >++ return >++ >+ m1 = getattr(cls, 'run', None) >+ def run(self): >+ if getattr(self, 'nocache', False): >+@@ -208,9 +227,6 @@ def make_cached(cls): >+ return m2(self) >+ ret = m2(self) >+ self.put_files_cache() >+- if hasattr(self, 'chmod'): >+- for node in self.outputs: >+- os.chmod(node.abspath(), self.chmod) >+ return ret >+ cls.post_run = post_run >+ cls.has_cache = True >+@@ -257,6 +273,19 @@ def build(bld): >+ for x in reversed(list(Task.classes.values())): >+ make_cached(x) >+ >++ if WAFCACHE_STATS: >++ # Init counter for statistics and hook to print results at the end >++ bld.cache_reqs = bld.cache_hits = bld.cache_puts = 0 >++ >++ def printstats(bld): >++ hit_ratio = 0 >++ if bld.cache_reqs > 0: >++ hit_ratio = (bld.cache_hits / bld.cache_reqs) * 100 >++ Logs.pprint('CYAN', ' wafcache stats: requests: %s, hits, %s, ratio: %.2f%%, writes %s' % >++ (bld.cache_reqs, bld.cache_hits, hit_ratio, bld.cache_puts) ) >++ >++ bld.add_post_fun(printstats) >++ >+ def cache_command(sig, files_from, files_to): >+ """ >+ Create a command for cache worker processes, returns a pickled >+@@ -320,7 +349,10 @@ def lru_trim(): >+ >+ size = 0 >+ for fname in os.listdir(path): >+- size += os.lstat(os.path.join(path, fname)).st_size >++ try: >++ size += os.lstat(os.path.join(path, fname)).st_size >++ except OSError: >++ pass >+ lst.append((os.stat(path).st_mtime, size, path)) >+ >+ lst.sort(key=lambda x: x[0]) >+@@ -331,7 +363,7 @@ def lru_trim(): >+ _, tmp_size, path = lst.pop() >+ tot -= tmp_size >+ >+- tmp = path + '.tmp' >++ tmp = path + '.remove' >+ try: >+ shutil.rmtree(tmp) >+ except OSError: >+@@ -339,12 +371,12 @@ def lru_trim(): >+ try: >+ os.rename(path, tmp) >+ except OSError: >+- sys.stderr.write('Could not rename %r to %r' % (path, tmp)) >++ sys.stderr.write('Could not rename %r to %r\n' % (path, tmp)) >+ else: >+ try: >+ shutil.rmtree(tmp) >+ except OSError: >+- sys.stderr.write('Could not remove %r' % tmp) >++ sys.stderr.write('Could not remove %r\n' % tmp) >+ sys.stderr.write("Cache trimmed: %r bytes in %r folders left\n" % (tot, len(lst))) >+ >+ >+@@ -371,8 +403,8 @@ def lru_evict(): >+ try: >+ fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) >+ except EnvironmentError: >+- sys.stderr.write('another process is running!\n') >+- pass >++ if WAFCACHE_VERBOSITY: >++ sys.stderr.write('wafcache: another cleaning process is running\n') >+ else: >+ # now dow the actual cleanup >+ lru_trim() >+@@ -443,7 +475,10 @@ class fcache(object): >+ else: >+ # attempt trimming if caching was successful: >+ # we may have things to trim! >+- lru_evict() >++ try: >++ lru_evict() >++ except Exception: >++ return traceback.format_exc() >+ return OK >+ >+ def copy_from_cache(self, sig, files_from, files_to): >+@@ -481,7 +516,7 @@ class bucket_cache(object): >+ out, err = proc.communicate() >+ if proc.returncode: >+ raise OSError('Error copy %r to %r using: %r (exit %r):\n out:%s\n err:%s' % ( >+- source, target, cmd, proc.returncode, out.decode(), err.decode())) >++ source, target, cmd, proc.returncode, out.decode(errors='replace'), err.decode(errors='replace'))) >+ >+ def copy_to_cache(self, sig, files_from, files_to): >+ try: >+-- >+2.37.3 >+ >diff --git a/net/samba413/files/patch-waf-2.0.23 b/net/samba413/files/patch-waf-2.0.23 >new file mode 100644 >index 000000000000..36a70e32e8c3 >--- /dev/null >+++ b/net/samba413/files/patch-waf-2.0.23 >@@ -0,0 +1,877 @@ >+From fb175576b698f43224dab815fd6c0763a12db2b2 Mon Sep 17 00:00:00 2001 >+From: Andreas Schneider <asn@samba.org> >+Date: Thu, 17 Feb 2022 15:40:20 +0100 >+Subject: [PATCH] third_party: Update waf to verison 2.0.23 >+ >+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 Feb 21 10:06:27 UTC 2022 on sn-devel-184 >+--- >+ buildtools/bin/waf | 3 +- >+ buildtools/wafsamba/wafsamba.py | 2 +- >+ third_party/waf/waflib/Context.py | 6 +- >+ third_party/waf/waflib/Runner.py | 4 +- >+ third_party/waf/waflib/TaskGen.py | 8 +- >+ third_party/waf/waflib/Tools/c_config.py | 1 + >+ third_party/waf/waflib/Tools/compiler_c.py | 25 +++--- >+ third_party/waf/waflib/Tools/compiler_cxx.py | 25 +++--- >+ third_party/waf/waflib/Tools/python.py | 7 +- >+ third_party/waf/waflib/Tools/qt5.py | 4 +- >+ third_party/waf/waflib/Tools/winres.py | 35 ++++++++ >+ .../extras/clang_compilation_database.py | 2 +- >+ .../waf/waflib/extras/classic_runner.py | 68 +++++++++++++++ >+ third_party/waf/waflib/extras/color_gcc.py | 2 +- >+ third_party/waf/waflib/extras/eclipse.py | 74 ++++++++++++++++- >+ third_party/waf/waflib/extras/gccdeps.py | 82 ++++++++++--------- >+ third_party/waf/waflib/extras/msvcdeps.py | 54 ++++++++---- >+ third_party/waf/waflib/extras/msvs.py | 6 +- >+ third_party/waf/waflib/extras/swig.py | 2 +- >+ third_party/waf/waflib/extras/wafcache.py | 26 +++--- >+ third_party/waf/waflib/fixpy2.py | 2 +- >+ 21 files changed, 325 insertions(+), 113 deletions(-) >+ create mode 100644 third_party/waf/waflib/extras/classic_runner.py >+ >+diff --git buildtools/bin/waf buildtools/bin/waf >+index b0ccb09a877..2001ccdbd8a 100755 >+--- buildtools/bin/waf >++++ buildtools/bin/waf >+@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. >+ >+ import os, sys, inspect >+ >+-VERSION="2.0.22" >++VERSION="2.0.23" >+ REVISION="x" >+ GIT="x" >+ INSTALL="x" >+@@ -164,4 +164,3 @@ if __name__ == '__main__': >+ >+ from waflib import Scripting >+ Scripting.waf_entry_point(cwd, VERSION, wafdir[0]) >+- >+diff --git buildtools/wafsamba/wafsamba.py buildtools/wafsamba/wafsamba.py >+index 185ef3b73a2..710b82af663 100644 >+--- buildtools/wafsamba/wafsamba.py >++++ buildtools/wafsamba/wafsamba.py >+@@ -38,7 +38,7 @@ LIB_PATH="shared" >+ >+ os.environ['PYTHONUNBUFFERED'] = '1' >+ >+-if Context.HEXVERSION not in (0x2001600,): >++if Context.HEXVERSION not in (0x2001700,): >+ Logs.error(''' >+ Please use the version of waf that comes with Samba, not >+ a system installed version. See http://wiki.samba.org/index.php/Waf >+diff --git third_party/waf/waflib/Context.py third_party/waf/waflib/Context.py >+index 07ee1201f03..36d1ca74fef 100644 >+--- third_party/waf/waflib/Context.py >++++ third_party/waf/waflib/Context.py >+@@ -18,13 +18,13 @@ else: >+ import imp >+ >+ # the following 3 constants are updated on each new release (do not touch) >+-HEXVERSION=0x2001600 >++HEXVERSION=0x2001700 >+ """Constant updated on new releases""" >+ >+-WAFVERSION="2.0.22" >++WAFVERSION="2.0.23" >+ """Constant updated on new releases""" >+ >+-WAFREVISION="816d5bc48ba2abc4ac22f2b44d94d322bf992b9c" >++WAFREVISION="cc6b34cf555d354c34f554c41206134072588de7" >+ """Git revision when the waf version is updated""" >+ >+ WAFNAME="waf" >+diff --git third_party/waf/waflib/Runner.py third_party/waf/waflib/Runner.py >+index 91d55479e20..350c86a22c0 100644 >+--- third_party/waf/waflib/Runner.py >++++ third_party/waf/waflib/Runner.py >+@@ -71,7 +71,7 @@ class Consumer(Utils.threading.Thread): >+ """Task to execute""" >+ self.spawner = spawner >+ """Coordinator object""" >+- self.setDaemon(1) >++ self.daemon = True >+ self.start() >+ def run(self): >+ """ >+@@ -98,7 +98,7 @@ class Spawner(Utils.threading.Thread): >+ """:py:class:`waflib.Runner.Parallel` producer instance""" >+ self.sem = Utils.threading.Semaphore(master.numjobs) >+ """Bounded semaphore that prevents spawning more than *n* concurrent consumers""" >+- self.setDaemon(1) >++ self.daemon = True >+ self.start() >+ def run(self): >+ """ >+diff --git third_party/waf/waflib/TaskGen.py third_party/waf/waflib/TaskGen.py >+index f8f92bd57c1..89f63169910 100644 >+--- third_party/waf/waflib/TaskGen.py >++++ third_party/waf/waflib/TaskGen.py >+@@ -631,12 +631,8 @@ def process_rule(self): >+ cls.scan = self.scan >+ elif has_deps: >+ def scan(self): >+- nodes = [] >+- for x in self.generator.to_list(getattr(self.generator, 'deps', None)): >+- node = self.generator.path.find_resource(x) >+- if not node: >+- self.generator.bld.fatal('Could not find %r (was it declared?)' % x) >+- nodes.append(node) >++ deps = getattr(self.generator, 'deps', None) >++ nodes = self.generator.to_nodes(deps) >+ return [nodes, []] >+ cls.scan = scan >+ >+diff --git third_party/waf/waflib/Tools/c_config.py third_party/waf/waflib/Tools/c_config.py >+index 03b6bf61bc0..f5ab19bf6ce 100644 >+--- third_party/waf/waflib/Tools/c_config.py >++++ third_party/waf/waflib/Tools/c_config.py >+@@ -69,6 +69,7 @@ MACRO_TO_DEST_CPU = { >+ '__sh__' : 'sh', >+ '__xtensa__' : 'xtensa', >+ '__e2k__' : 'e2k', >++'__riscv' : 'riscv', >+ } >+ >+ @conf >+diff --git third_party/waf/waflib/Tools/compiler_c.py third_party/waf/waflib/Tools/compiler_c.py >+index 931dc57efec..e033ce6c5c3 100644 >+--- third_party/waf/waflib/Tools/compiler_c.py >++++ third_party/waf/waflib/Tools/compiler_c.py >+@@ -36,18 +36,19 @@ from waflib import Utils >+ from waflib.Logs import debug >+ >+ c_compiler = { >+-'win32': ['msvc', 'gcc', 'clang'], >+-'cygwin': ['gcc', 'clang'], >+-'darwin': ['clang', 'gcc'], >+-'aix': ['xlc', 'gcc', 'clang'], >+-'linux': ['gcc', 'clang', 'icc'], >+-'sunos': ['suncc', 'gcc'], >+-'irix': ['gcc', 'irixcc'], >+-'hpux': ['gcc'], >+-'osf1V': ['gcc'], >+-'gnu': ['gcc', 'clang'], >+-'java': ['gcc', 'msvc', 'clang', 'icc'], >+-'default':['clang', 'gcc'], >++'win32': ['msvc', 'gcc', 'clang'], >++'cygwin': ['gcc', 'clang'], >++'darwin': ['clang', 'gcc'], >++'aix': ['xlc', 'gcc', 'clang'], >++'linux': ['gcc', 'clang', 'icc'], >++'sunos': ['suncc', 'gcc'], >++'irix': ['gcc', 'irixcc'], >++'hpux': ['gcc'], >++'osf1V': ['gcc'], >++'gnu': ['gcc', 'clang'], >++'java': ['gcc', 'msvc', 'clang', 'icc'], >++'gnukfreebsd': ['gcc', 'clang'], >++'default': ['clang', 'gcc'], >+ } >+ """ >+ Dict mapping platform names to Waf tools finding specific C compilers:: >+diff --git third_party/waf/waflib/Tools/compiler_cxx.py third_party/waf/waflib/Tools/compiler_cxx.py >+index 09fca7e4dc6..42658c5847e 100644 >+--- third_party/waf/waflib/Tools/compiler_cxx.py >++++ third_party/waf/waflib/Tools/compiler_cxx.py >+@@ -37,18 +37,19 @@ from waflib import Utils >+ from waflib.Logs import debug >+ >+ cxx_compiler = { >+-'win32': ['msvc', 'g++', 'clang++'], >+-'cygwin': ['g++', 'clang++'], >+-'darwin': ['clang++', 'g++'], >+-'aix': ['xlc++', 'g++', 'clang++'], >+-'linux': ['g++', 'clang++', 'icpc'], >+-'sunos': ['sunc++', 'g++'], >+-'irix': ['g++'], >+-'hpux': ['g++'], >+-'osf1V': ['g++'], >+-'gnu': ['g++', 'clang++'], >+-'java': ['g++', 'msvc', 'clang++', 'icpc'], >+-'default': ['clang++', 'g++'] >++'win32': ['msvc', 'g++', 'clang++'], >++'cygwin': ['g++', 'clang++'], >++'darwin': ['clang++', 'g++'], >++'aix': ['xlc++', 'g++', 'clang++'], >++'linux': ['g++', 'clang++', 'icpc'], >++'sunos': ['sunc++', 'g++'], >++'irix': ['g++'], >++'hpux': ['g++'], >++'osf1V': ['g++'], >++'gnu': ['g++', 'clang++'], >++'java': ['g++', 'msvc', 'clang++', 'icpc'], >++'gnukfreebsd': ['g++', 'clang++'], >++'default': ['clang++', 'g++'] >+ } >+ """ >+ Dict mapping the platform names to Waf tools finding specific C++ compilers:: >+diff --git third_party/waf/waflib/Tools/python.py third_party/waf/waflib/Tools/python.py >+index 07442561dff..fb641e5e20d 100644 >+--- third_party/waf/waflib/Tools/python.py >++++ third_party/waf/waflib/Tools/python.py >+@@ -416,9 +416,14 @@ def check_python_headers(conf, features='pyembed pyext'): >+ >+ if not result: >+ path = [os.path.join(dct['prefix'], "libs")] >+- conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n") >++ conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY rather than pythonX.Y (win32)\n") >+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name) >+ >++ if not result: >++ path = [os.path.normpath(os.path.join(dct['INCLUDEPY'], '..', 'libs'))] >++ conf.to_log("\n\n# try again with -L$INCLUDEPY/../libs, and pythonXY rather than pythonX.Y (win32)\n") >++ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $INCLUDEPY/../libs' % name) >++ >+ if result: >+ break # do not forget to set LIBPATH_PYEMBED >+ >+diff --git third_party/waf/waflib/Tools/qt5.py third_party/waf/waflib/Tools/qt5.py >+index 82c83e18c8a..b3e61325e50 100644 >+--- third_party/waf/waflib/Tools/qt5.py >++++ third_party/waf/waflib/Tools/qt5.py >+@@ -783,8 +783,8 @@ def set_qt5_libs_to_check(self): >+ pat = self.env.cxxstlib_PATTERN >+ if Utils.unversioned_sys_platform() == 'darwin': >+ pat = r"%s\.framework" >+- re_qt = re.compile(pat % 'Qt5?(?P<name>\\D+)' + '$') >+- for x in dirlst: >++ re_qt = re.compile(pat % 'Qt5?(?P<name>\\w+)' + '$') >++ for x in sorted(dirlst): >+ m = re_qt.match(x) >+ if m: >+ self.qt5_vars.append("Qt5%s" % m.group('name')) >+diff --git third_party/waf/waflib/Tools/winres.py third_party/waf/waflib/Tools/winres.py >+index 9be1ed66009..73c0e95315b 100644 >+--- third_party/waf/waflib/Tools/winres.py >++++ third_party/waf/waflib/Tools/winres.py >+@@ -4,10 +4,12 @@ >+ >+ "Process *.rc* files for C/C++: X{.rc -> [.res|.rc.o]}" >+ >++import os >+ import re >+ from waflib import Task >+ from waflib.TaskGen import extension >+ from waflib.Tools import c_preproc >++from waflib import Utils >+ >+ @extension('.rc') >+ def rc_file(self, node): >+@@ -61,6 +63,39 @@ class winrc(Task.Task): >+ tmp.start(self.inputs[0], self.env) >+ return (tmp.nodes, tmp.names) >+ >++ def exec_command(self, cmd, **kw): >++ if self.env.WINRC_TGT_F == '/fo': >++ # Since winres include paths may contain spaces, they do not fit in >++ # response files and are best passed as environment variables >++ replace_cmd = [] >++ incpaths = [] >++ while cmd: >++ # filter include path flags >++ flag = cmd.pop(0) >++ if flag.upper().startswith('/I'): >++ if len(flag) == 2: >++ incpaths.append(cmd.pop(0)) >++ else: >++ incpaths.append(flag[2:]) >++ else: >++ replace_cmd.append(flag) >++ cmd = replace_cmd >++ if incpaths: >++ # append to existing environment variables in INCLUDE >++ env = kw['env'] = dict(kw.get('env') or self.env.env or os.environ) >++ pre_includes = env.get('INCLUDE', '') >++ env['INCLUDE'] = pre_includes + os.pathsep + os.pathsep.join(incpaths) >++ >++ return super(winrc, self).exec_command(cmd, **kw) >++ >++ def quote_flag(self, flag): >++ if self.env.WINRC_TGT_F == '/fo': >++ # winres does not support quotes around flags in response files >++ return flag >++ >++ return super(winrc, self).quote_flag(flag) >++ >++ >+ def configure(conf): >+ """ >+ Detects the programs RC or windres, depending on the C/C++ compiler in use >+diff --git third_party/waf/waflib/extras/clang_compilation_database.py third_party/waf/waflib/extras/clang_compilation_database.py >+index 17f66949376..bd29db93fd5 100644 >+--- third_party/waf/waflib/extras/clang_compilation_database.py >++++ third_party/waf/waflib/extras/clang_compilation_database.py >+@@ -126,7 +126,7 @@ def patch_execute(): >+ Invoke clangdb command before build >+ """ >+ if self.cmd.startswith('build'): >+- Scripting.run_command('clangdb') >++ Scripting.run_command(self.cmd.replace('build','clangdb')) >+ >+ old_execute_build(self) >+ >+diff --git third_party/waf/waflib/extras/classic_runner.py third_party/waf/waflib/extras/classic_runner.py >+new file mode 100644 >+index 00000000000..b08c794e880 >+--- /dev/null >++++ third_party/waf/waflib/extras/classic_runner.py >+@@ -0,0 +1,68 @@ >++#!/usr/bin/env python >++# encoding: utf-8 >++# Thomas Nagy, 2021 (ita) >++ >++from waflib import Utils, Runner >++ >++""" >++Re-enable the classic threading system from waf 1.x >++ >++def configure(conf): >++ conf.load('classic_runner') >++""" >++ >++class TaskConsumer(Utils.threading.Thread): >++ """ >++ Task consumers belong to a pool of workers >++ >++ They wait for tasks in the queue and then use ``task.process(...)`` >++ """ >++ def __init__(self, spawner): >++ Utils.threading.Thread.__init__(self) >++ """ >++ Obtain :py:class:`waflib.Task.TaskBase` instances from this queue. >++ """ >++ self.spawner = spawner >++ self.daemon = True >++ self.start() >++ >++ def run(self): >++ """ >++ Loop over the tasks to execute >++ """ >++ try: >++ self.loop() >++ except Exception: >++ pass >++ >++ def loop(self): >++ """ >++ Obtain tasks from :py:attr:`waflib.Runner.TaskConsumer.ready` and call >++ :py:meth:`waflib.Task.TaskBase.process`. If the object is a function, execute it. >++ """ >++ master = self.spawner.master >++ while 1: >++ if not master.stop: >++ try: >++ tsk = master.ready.get() >++ if tsk: >++ tsk.log_display(tsk.generator.bld) >++ master.process_task(tsk) >++ else: >++ break >++ finally: >++ master.out.put(tsk) >++ >++class Spawner(object): >++ """ >++ Daemon thread that consumes tasks from :py:class:`waflib.Runner.Parallel` producer and >++ spawns a consuming thread :py:class:`waflib.Runner.Consumer` for each >++ :py:class:`waflib.Task.Task` instance. >++ """ >++ def __init__(self, master): >++ self.master = master >++ """:py:class:`waflib.Runner.Parallel` producer instance""" >++ >++ self.pool = [TaskConsumer(self) for i in range(master.numjobs)] >++ >++Runner.Spawner = Spawner >+diff --git third_party/waf/waflib/extras/color_gcc.py third_party/waf/waflib/extras/color_gcc.py >+index b68c5ebf2df..09729035fec 100644 >+--- third_party/waf/waflib/extras/color_gcc.py >++++ third_party/waf/waflib/extras/color_gcc.py >+@@ -19,7 +19,7 @@ class ColorGCCFormatter(Logs.formatter): >+ func = frame.f_code.co_name >+ if func == 'exec_command': >+ cmd = frame.f_locals.get('cmd') >+- if isinstance(cmd, list) and ('gcc' in cmd[0] or 'g++' in cmd[0]): >++ if isinstance(cmd, list) and (len(cmd) > 0) and ('gcc' in cmd[0] or 'g++' in cmd[0]): >+ lines = [] >+ for line in rec.msg.splitlines(): >+ if 'warning: ' in line: >+diff --git third_party/waf/waflib/extras/eclipse.py third_party/waf/waflib/extras/eclipse.py >+index bb787416e9f..49ca9686b7b 100644 >+--- third_party/waf/waflib/extras/eclipse.py >++++ third_party/waf/waflib/extras/eclipse.py >+@@ -10,6 +10,9 @@ Usage: >+ def options(opt): >+ opt.load('eclipse') >+ >++To add additional targets beside standard ones (configure, dist, install, check) >++the environment ECLIPSE_EXTRA_TARGETS can be set (ie. to ['test', 'lint', 'docs']) >++ >+ $ waf configure eclipse >+ """ >+ >+@@ -25,6 +28,8 @@ cdt_core = oe_cdt + '.core' >+ cdt_bld = oe_cdt + '.build.core' >+ extbuilder_dir = '.externalToolBuilders' >+ extbuilder_name = 'Waf_Builder.launch' >++settings_dir = '.settings' >++settings_name = 'language.settings.xml' >+ >+ class eclipse(Build.BuildContext): >+ cmd = 'eclipse' >+@@ -131,9 +136,11 @@ class eclipse(Build.BuildContext): >+ path = p.path_from(self.srcnode) >+ >+ if (path.startswith("/")): >+- cpppath.append(path) >++ if path not in cpppath: >++ cpppath.append(path) >+ else: >+- workspace_includes.append(path) >++ if path not in workspace_includes: >++ workspace_includes.append(path) >+ >+ if is_cc and path not in source_dirs: >+ source_dirs.append(path) >+@@ -156,6 +163,61 @@ class eclipse(Build.BuildContext): >+ project = self.impl_create_javaproject(javasrcpath, javalibpath) >+ self.write_conf_to_xml('.classpath', project) >+ >++ # Create editor language settings to have correct standards applied in IDE, as per project configuration >++ try: >++ os.mkdir(settings_dir) >++ except OSError: >++ pass # Ignore if dir already exists >++ >++ lang_settings = Document() >++ project = lang_settings.createElement('project') >++ >++ # Language configurations for C and C++ via cdt >++ if hasc: >++ configuration = self.add(lang_settings, project, 'configuration', >++ {'id' : 'org.eclipse.cdt.core.default.config.1', 'name': 'Default'}) >++ >++ extension = self.add(lang_settings, configuration, 'extension', {'point': 'org.eclipse.cdt.core.LanguageSettingsProvider'}) >++ >++ provider = self.add(lang_settings, extension, 'provider', >++ { 'copy-of': 'extension', >++ 'id': 'org.eclipse.cdt.ui.UserLanguageSettingsProvider'}) >++ >++ provider = self.add(lang_settings, extension, 'provider-reference', >++ { 'id': 'org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider', >++ 'ref': 'shared-provider'}) >++ >++ provider = self.add(lang_settings, extension, 'provider-reference', >++ { 'id': 'org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider', >++ 'ref': 'shared-provider'}) >++ >++ # C and C++ are kept as separated providers so appropriate flags are used also in mixed projects >++ if self.env.CC: >++ provider = self.add(lang_settings, extension, 'provider', >++ { 'class': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector', >++ 'console': 'false', >++ 'id': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector.1', >++ 'keep-relative-paths' : 'false', >++ 'name': 'CDT GCC Built-in Compiler Settings', >++ 'parameter': '%s %s ${FLAGS} -E -P -v -dD "${INPUTS}"'%(self.env.CC[0],' '.join(self.env['CFLAGS'])), >++ 'prefer-non-shared': 'true' }) >++ >++ self.add(lang_settings, provider, 'language-scope', { 'id': 'org.eclipse.cdt.core.gcc'}) >++ >++ if self.env.CXX: >++ provider = self.add(lang_settings, extension, 'provider', >++ { 'class': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector', >++ 'console': 'false', >++ 'id': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector.2', >++ 'keep-relative-paths' : 'false', >++ 'name': 'CDT GCC Built-in Compiler Settings', >++ 'parameter': '%s %s ${FLAGS} -E -P -v -dD "${INPUTS}"'%(self.env.CXX[0],' '.join(self.env['CXXFLAGS'])), >++ 'prefer-non-shared': 'true' }) >++ self.add(lang_settings, provider, 'language-scope', { 'id': 'org.eclipse.cdt.core.g++'}) >++ >++ lang_settings.appendChild(project) >++ self.write_conf_to_xml('%s%s%s'%(settings_dir, os.path.sep, settings_name), lang_settings) >++ >+ def impl_create_project(self, executable, appname, hasc, hasjava, haspython, waf_executable): >+ doc = Document() >+ projectDescription = doc.createElement('projectDescription') >+@@ -341,6 +403,8 @@ class eclipse(Build.BuildContext): >+ addTargetWrap('dist', False) >+ addTargetWrap('install', False) >+ addTargetWrap('check', False) >++ for addTgt in self.env.ECLIPSE_EXTRA_TARGETS or []: >++ addTargetWrap(addTgt, False) >+ >+ storageModule = self.add(doc, cproject, 'storageModule', >+ {'moduleId': 'cdtBuildSystem', >+@@ -348,6 +412,12 @@ class eclipse(Build.BuildContext): >+ >+ self.add(doc, storageModule, 'project', {'id': '%s.null.1'%appname, 'name': appname}) >+ >++ storageModule = self.add(doc, cproject, 'storageModule', >++ {'moduleId': 'org.eclipse.cdt.core.LanguageSettingsProviders'}) >++ >++ storageModule = self.add(doc, cproject, 'storageModule', >++ {'moduleId': 'scannerConfiguration'}) >++ >+ doc.appendChild(cproject) >+ return doc >+ >+diff --git third_party/waf/waflib/extras/gccdeps.py third_party/waf/waflib/extras/gccdeps.py >+index 1fc9373489a..9e9952f2f7d 100644 >+--- third_party/waf/waflib/extras/gccdeps.py >++++ third_party/waf/waflib/extras/gccdeps.py >+@@ -29,13 +29,6 @@ if not c_preproc.go_absolute: >+ # Third-party tools are allowed to add extra names in here with append() >+ supported_compilers = ['gas', 'gcc', 'icc', 'clang'] >+ >+-def scan(self): >+- if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: >+- return super(self.derived_gccdeps, self).scan() >+- nodes = self.generator.bld.node_deps.get(self.uid(), []) >+- names = [] >+- return (nodes, names) >+- >+ re_o = re.compile(r"\.o$") >+ re_splitter = re.compile(r'(?<!\\)\s+') # split by space, except when spaces are escaped >+ >+@@ -61,28 +54,30 @@ def path_to_node(base_node, path, cached_nodes): >+ else: >+ # Not hashable, assume it is a list and join into a string >+ node_lookup_key = (base_node, os.path.sep.join(path)) >++ >+ try: >+- lock.acquire() >+ node = cached_nodes[node_lookup_key] >+ except KeyError: >+- node = base_node.find_resource(path) >+- cached_nodes[node_lookup_key] = node >+- finally: >+- lock.release() >++ # retry with lock on cache miss >++ with lock: >++ try: >++ node = cached_nodes[node_lookup_key] >++ except KeyError: >++ node = cached_nodes[node_lookup_key] = base_node.find_resource(path) >++ >+ return node >+ >+ def post_run(self): >+ if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: >+ return super(self.derived_gccdeps, self).post_run() >+ >+- name = self.outputs[0].abspath() >+- name = re_o.sub('.d', name) >++ deps_filename = self.outputs[0].abspath() >++ deps_filename = re_o.sub('.d', deps_filename) >+ try: >+- txt = Utils.readf(name) >++ deps_txt = Utils.readf(deps_filename) >+ except EnvironmentError: >+ Logs.error('Could not find a .d dependency file, are cflags/cxxflags overwritten?') >+ raise >+- #os.remove(name) >+ >+ # Compilers have the choice to either output the file's dependencies >+ # as one large Makefile rule: >+@@ -102,15 +97,16 @@ def post_run(self): >+ # So the first step is to sanitize the input by stripping out the left- >+ # hand side of all these lines. After that, whatever remains are the >+ # implicit dependencies of task.outputs[0] >+- txt = '\n'.join([remove_makefile_rule_lhs(line) for line in txt.splitlines()]) >++ deps_txt = '\n'.join([remove_makefile_rule_lhs(line) for line in deps_txt.splitlines()]) >+ >+ # Now join all the lines together >+- txt = txt.replace('\\\n', '') >++ deps_txt = deps_txt.replace('\\\n', '') >+ >+- val = txt.strip() >+- val = [x.replace('\\ ', ' ') for x in re_splitter.split(val) if x] >++ dep_paths = deps_txt.strip() >++ dep_paths = [x.replace('\\ ', ' ') for x in re_splitter.split(dep_paths) if x] >+ >+- nodes = [] >++ resolved_nodes = [] >++ unresolved_names = [] >+ bld = self.generator.bld >+ >+ # Dynamically bind to the cache >+@@ -119,39 +115,41 @@ def post_run(self): >+ except AttributeError: >+ cached_nodes = bld.cached_nodes = {} >+ >+- for x in val: >++ for path in dep_paths: >+ >+ node = None >+- if os.path.isabs(x): >+- node = path_to_node(bld.root, x, cached_nodes) >++ if os.path.isabs(path): >++ node = path_to_node(bld.root, path, cached_nodes) >+ else: >+ # TODO waf 1.9 - single cwd value >+- path = getattr(bld, 'cwdx', bld.bldnode) >++ base_node = getattr(bld, 'cwdx', bld.bldnode) >+ # when calling find_resource, make sure the path does not contain '..' >+- x = [k for k in Utils.split_path(x) if k and k != '.'] >+- while '..' in x: >+- idx = x.index('..') >++ path = [k for k in Utils.split_path(path) if k and k != '.'] >++ while '..' in path: >++ idx = path.index('..') >+ if idx == 0: >+- x = x[1:] >+- path = path.parent >++ path = path[1:] >++ base_node = base_node.parent >+ else: >+- del x[idx] >+- del x[idx-1] >++ del path[idx] >++ del path[idx-1] >+ >+- node = path_to_node(path, x, cached_nodes) >++ node = path_to_node(base_node, path, cached_nodes) >+ >+ if not node: >+- raise ValueError('could not find %r for %r' % (x, self)) >++ raise ValueError('could not find %r for %r' % (path, self)) >++ >+ if id(node) == id(self.inputs[0]): >+ # ignore the source file, it is already in the dependencies >+ # this way, successful config tests may be retrieved from the cache >+ continue >+- nodes.append(node) >+ >+- Logs.debug('deps: gccdeps for %s returned %s', self, nodes) >++ resolved_nodes.append(node) >+ >+- bld.node_deps[self.uid()] = nodes >+- bld.raw_deps[self.uid()] = [] >++ Logs.debug('deps: gccdeps for %s returned %s', self, resolved_nodes) >++ >++ bld.node_deps[self.uid()] = resolved_nodes >++ bld.raw_deps[self.uid()] = unresolved_names >+ >+ try: >+ del self.cache_sig >+@@ -160,6 +158,14 @@ def post_run(self): >+ >+ Task.Task.post_run(self) >+ >++def scan(self): >++ if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: >++ return super(self.derived_gccdeps, self).scan() >++ >++ resolved_nodes = self.generator.bld.node_deps.get(self.uid(), []) >++ unresolved_names = [] >++ return (resolved_nodes, unresolved_names) >++ >+ def sig_implicit_deps(self): >+ if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: >+ return super(self.derived_gccdeps, self).sig_implicit_deps() >+diff --git third_party/waf/waflib/extras/msvcdeps.py third_party/waf/waflib/extras/msvcdeps.py >+index 52985dce058..e8985bde7c7 100644 >+--- third_party/waf/waflib/extras/msvcdeps.py >++++ third_party/waf/waflib/extras/msvcdeps.py >+@@ -32,7 +32,6 @@ from waflib.Tools import c_preproc, c, cxx, msvc >+ from waflib.TaskGen import feature, before_method >+ >+ lock = threading.Lock() >+-nodes = {} # Cache the path -> Node lookup >+ >+ PREPROCESSOR_FLAG = '/showIncludes' >+ INCLUDE_PATTERN = 'Note: including file:' >+@@ -50,23 +49,47 @@ def apply_msvcdeps_flags(taskgen): >+ if taskgen.env.get_flat(flag).find(PREPROCESSOR_FLAG) < 0: >+ taskgen.env.append_value(flag, PREPROCESSOR_FLAG) >+ >++ >++def get_correct_path_case(base_path, path): >++ ''' >++ Return a case-corrected version of ``path`` by searching the filesystem for >++ ``path``, relative to ``base_path``, using the case returned by the filesystem. >++ ''' >++ components = Utils.split_path(path) >++ >++ corrected_path = '' >++ if os.path.isabs(path): >++ corrected_path = components.pop(0).upper() + os.sep >++ >++ for part in components: >++ part = part.lower() >++ search_path = os.path.join(base_path, corrected_path) >++ if part == '..': >++ corrected_path = os.path.join(corrected_path, part) >++ search_path = os.path.normpath(search_path) >++ continue >++ >++ for item in sorted(os.listdir(search_path)): >++ if item.lower() == part: >++ corrected_path = os.path.join(corrected_path, item) >++ break >++ else: >++ raise ValueError("Can't find %r in %r" % (part, search_path)) >++ >++ return corrected_path >++ >++ >+ def path_to_node(base_node, path, cached_nodes): >+ ''' >+ Take the base node and the path and return a node >+ Results are cached because searching the node tree is expensive >+ The following code is executed by threads, it is not safe, so a lock is needed... >+ ''' >+- # normalize the path because ant_glob() does not understand >+- # parent path components (..) >++ # normalize the path to remove parent path components (..) >+ path = os.path.normpath(path) >+ >+ # normalize the path case to increase likelihood of a cache hit >+- path = os.path.normcase(path) >+- >+- # ant_glob interprets [] and () characters, so those must be replaced >+- path = path.replace('[', '?').replace(']', '?').replace('(', '[(]').replace(')', '[)]') >+- >+- node_lookup_key = (base_node, path) >++ node_lookup_key = (base_node, os.path.normcase(path)) >+ >+ try: >+ node = cached_nodes[node_lookup_key] >+@@ -76,8 +99,8 @@ def path_to_node(base_node, path, cached_nodes): >+ try: >+ node = cached_nodes[node_lookup_key] >+ except KeyError: >+- node_list = base_node.ant_glob([path], ignorecase=True, remove=False, quiet=True, regex=False) >+- node = cached_nodes[node_lookup_key] = node_list[0] if node_list else None >++ path = get_correct_path_case(base_node.abspath(), path) >++ node = cached_nodes[node_lookup_key] = base_node.find_node(path) >+ >+ return node >+ >+@@ -89,9 +112,9 @@ def post_run(self): >+ if getattr(self, 'cached', None): >+ return Task.Task.post_run(self) >+ >+- bld = self.generator.bld >+- unresolved_names = [] >+ resolved_nodes = [] >++ unresolved_names = [] >++ bld = self.generator.bld >+ >+ # Dynamically bind to the cache >+ try: >+@@ -124,11 +147,14 @@ def post_run(self): >+ continue >+ >+ if id(node) == id(self.inputs[0]): >+- # Self-dependency >++ # ignore the source file, it is already in the dependencies >++ # this way, successful config tests may be retrieved from the cache >+ continue >+ >+ resolved_nodes.append(node) >+ >++ Logs.debug('deps: msvcdeps for %s returned %s', self, resolved_nodes) >++ >+ bld.node_deps[self.uid()] = resolved_nodes >+ bld.raw_deps[self.uid()] = unresolved_names >+ >+diff --git third_party/waf/waflib/extras/msvs.py third_party/waf/waflib/extras/msvs.py >+index 8aa2db0b751..03b739f849c 100644 >+--- third_party/waf/waflib/extras/msvs.py >++++ third_party/waf/waflib/extras/msvs.py >+@@ -787,8 +787,12 @@ class msvs_generator(BuildContext): >+ self.collect_dirs() >+ default_project = getattr(self, 'default_project', None) >+ def sortfun(x): >+- if x.name == default_project: >++ # folders should sort to the top >++ if getattr(x, 'VS_GUID_SOLUTIONFOLDER', None): >+ return '' >++ # followed by the default project >++ elif x.name == default_project: >++ return ' ' >+ return getattr(x, 'path', None) and x.path.win32path() or x.name >+ self.all_projects.sort(key=sortfun) >+ >+diff --git third_party/waf/waflib/extras/swig.py third_party/waf/waflib/extras/swig.py >+index 740ab46d963..967caeb5a82 100644 >+--- third_party/waf/waflib/extras/swig.py >++++ third_party/waf/waflib/extras/swig.py >+@@ -17,7 +17,7 @@ tasks have to be added dynamically: >+ >+ SWIG_EXTS = ['.swig', '.i'] >+ >+-re_module = re.compile(r'%module(?:\s*\(.*\))?\s+(.+)', re.M) >++re_module = re.compile(r'%module(?:\s*\(.*\))?\s+([^\r\n]+)', re.M) >+ >+ re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M) >+ re_2 = re.compile(r'[#%](?:include|import(?:\(module=".*"\))+|python(?:begin|code)) [<"](.*)[">]', re.M) >+diff --git third_party/waf/waflib/extras/wafcache.py third_party/waf/waflib/extras/wafcache.py >+index cc23fcd6673..2cef46c0e1c 100644 >+--- third_party/waf/waflib/extras/wafcache.py >++++ third_party/waf/waflib/extras/wafcache.py >+@@ -258,6 +258,19 @@ def build(bld): >+ """ >+ Called during the build process to enable file caching >+ """ >++ if WAFCACHE_STATS: >++ # Init counter for statistics and hook to print results at the end >++ bld.cache_reqs = bld.cache_hits = bld.cache_puts = 0 >++ >++ def printstats(bld): >++ hit_ratio = 0 >++ if bld.cache_reqs > 0: >++ hit_ratio = (bld.cache_hits / bld.cache_reqs) * 100 >++ Logs.pprint('CYAN', ' wafcache stats: requests: %s, hits, %s, ratio: %.2f%%, writes %s' % >++ (bld.cache_reqs, bld.cache_hits, hit_ratio, bld.cache_puts) ) >++ >++ bld.add_post_fun(printstats) >++ >+ if process_pool: >+ # already called once >+ return >+@@ -273,19 +286,6 @@ def build(bld): >+ for x in reversed(list(Task.classes.values())): >+ make_cached(x) >+ >+- if WAFCACHE_STATS: >+- # Init counter for statistics and hook to print results at the end >+- bld.cache_reqs = bld.cache_hits = bld.cache_puts = 0 >+- >+- def printstats(bld): >+- hit_ratio = 0 >+- if bld.cache_reqs > 0: >+- hit_ratio = (bld.cache_hits / bld.cache_reqs) * 100 >+- Logs.pprint('CYAN', ' wafcache stats: requests: %s, hits, %s, ratio: %.2f%%, writes %s' % >+- (bld.cache_reqs, bld.cache_hits, hit_ratio, bld.cache_puts) ) >+- >+- bld.add_post_fun(printstats) >+- >+ def cache_command(sig, files_from, files_to): >+ """ >+ Create a command for cache worker processes, returns a pickled >+diff --git third_party/waf/waflib/fixpy2.py third_party/waf/waflib/fixpy2.py >+index 24176e06645..c99bff4b9ae 100644 >+--- third_party/waf/waflib/fixpy2.py >++++ third_party/waf/waflib/fixpy2.py >+@@ -56,7 +56,7 @@ def r1(code): >+ @subst('Runner.py') >+ def r4(code): >+ "generator syntax" >+- return code.replace('next(self.biter)', 'self.biter.next()') >++ return code.replace('next(self.biter)', 'self.biter.next()').replace('self.daemon = True', 'self.setDaemon(1)') >+ >+ @subst('Context.py') >+ def r5(code): >+-- >+2.37.3 >+ >diff --git a/net/samba413/files/patch-waf-2.0.24 b/net/samba413/files/patch-waf-2.0.24 >new file mode 100644 >index 000000000000..2c5c76e6ca3b >--- /dev/null >+++ b/net/samba413/files/patch-waf-2.0.24 >@@ -0,0 +1,164 @@ >+From d19dfe1efb2f6cb0dcf0a63b957df584d8ed5945 Mon Sep 17 00:00:00 2001 >+From: Andreas Schneider <asn@samba.org> >+Date: Mon, 23 May 2022 07:54:06 +0200 >+Subject: [PATCH] third_party: Update waf to version 2.0.24 >+ >+This fixes building of python libraries with Python 3.11! >+ >+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15071 >+ >+Signed-off-by: Andreas Schneider <asn@samba.org> >+Reviewed-by: Stefan Metzmacher <metze@samba.org> >+ >+Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org> >+Autobuild-Date(master): Mon May 23 09:34:51 UTC 2022 on sn-devel-184 >+--- >+ buildtools/bin/waf | 2 +- >+ buildtools/wafsamba/wafsamba.py | 2 +- >+ third_party/waf/waflib/Context.py | 8 ++++---- >+ third_party/waf/waflib/Tools/ccroot.py | 1 + >+ third_party/waf/waflib/Tools/msvc.py | 17 ++++++++++++++++- >+ third_party/waf/waflib/Tools/python.py | 4 ++-- >+ third_party/waf/waflib/Tools/tex.py | 1 + >+ 7 files changed, 26 insertions(+), 9 deletions(-) >+ >+diff --git buildtools/bin/waf buildtools/bin/waf >+index 2001ccdbd8a..d9cba343623 100755 >+--- buildtools/bin/waf >++++ buildtools/bin/waf >+@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. >+ >+ import os, sys, inspect >+ >+-VERSION="2.0.23" >++VERSION="2.0.24" >+ REVISION="x" >+ GIT="x" >+ INSTALL="x" >+diff --git buildtools/wafsamba/wafsamba.py buildtools/wafsamba/wafsamba.py >+index 4bd4e9f7fe3..79fe8b5e575 100644 >+--- buildtools/wafsamba/wafsamba.py >++++ buildtools/wafsamba/wafsamba.py >+@@ -38,7 +38,7 @@ LIB_PATH="shared" >+ >+ os.environ['PYTHONUNBUFFERED'] = '1' >+ >+-if Context.HEXVERSION not in (0x2001700,): >++if Context.HEXVERSION not in (0x2001800,): >+ Logs.error(''' >+ Please use the version of waf that comes with Samba, not >+ a system installed version. See http://wiki.samba.org/index.php/Waf >+diff --git third_party/waf/waflib/Context.py third_party/waf/waflib/Context.py >+index 36d1ca74fef..4a0130b24a0 100644 >+--- third_party/waf/waflib/Context.py >++++ third_party/waf/waflib/Context.py >+@@ -18,13 +18,13 @@ else: >+ import imp >+ >+ # the following 3 constants are updated on each new release (do not touch) >+-HEXVERSION=0x2001700 >++HEXVERSION=0x2001800 >+ """Constant updated on new releases""" >+ >+-WAFVERSION="2.0.23" >++WAFVERSION="2.0.24" >+ """Constant updated on new releases""" >+ >+-WAFREVISION="cc6b34cf555d354c34f554c41206134072588de7" >++WAFREVISION="1af97c71f5a6756abf36d0f78ed8fd551596d7cb" >+ """Git revision when the waf version is updated""" >+ >+ WAFNAME="waf" >+@@ -144,7 +144,7 @@ class Context(ctx): >+ :type fun: string >+ >+ .. inheritance-diagram:: waflib.Context.Context waflib.Build.BuildContext waflib.Build.InstallContext waflib.Build.UninstallContext waflib.Build.StepContext waflib.Build.ListContext waflib.Configure.ConfigurationContext waflib.Scripting.Dist waflib.Scripting.DistCheck waflib.Build.CleanContext >+- >++ :top-classes: waflib.Context.Context >+ """ >+ >+ errors = Errors >+diff --git third_party/waf/waflib/Tools/ccroot.py third_party/waf/waflib/Tools/ccroot.py >+index 579d5b2b72b..76deff54dcb 100644 >+--- third_party/waf/waflib/Tools/ccroot.py >++++ third_party/waf/waflib/Tools/ccroot.py >+@@ -128,6 +128,7 @@ class link_task(Task.Task): >+ Base class for all link tasks. A task generator is supposed to have at most one link task bound in the attribute *link_task*. See :py:func:`waflib.Tools.ccroot.apply_link`. >+ >+ .. inheritance-diagram:: waflib.Tools.ccroot.stlink_task waflib.Tools.c.cprogram waflib.Tools.c.cshlib waflib.Tools.cxx.cxxstlib waflib.Tools.cxx.cxxprogram waflib.Tools.cxx.cxxshlib waflib.Tools.d.dprogram waflib.Tools.d.dshlib waflib.Tools.d.dstlib waflib.Tools.ccroot.fake_shlib waflib.Tools.ccroot.fake_stlib waflib.Tools.asm.asmprogram waflib.Tools.asm.asmshlib waflib.Tools.asm.asmstlib >++ :top-classes: waflib.Tools.ccroot.link_task >+ """ >+ color = 'YELLOW' >+ >+diff --git third_party/waf/waflib/Tools/msvc.py third_party/waf/waflib/Tools/msvc.py >+index 0c4703aaee9..026a4c7fc48 100644 >+--- third_party/waf/waflib/Tools/msvc.py >++++ third_party/waf/waflib/Tools/msvc.py >+@@ -109,6 +109,21 @@ def options(opt): >+ opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='') >+ opt.add_option('--no-msvc-lazy', action='store_false', help = 'lazily check msvc target environments', default=True, dest='msvc_lazy') >+ >++class MSVCVersion(object): >++ def __init__(self, ver): >++ m = re.search('^(.*)\s+(\d+[.]\d+)', ver) >++ if m: >++ self.name = m.group(1) >++ self.number = float(m.group(2)) >++ else: >++ self.name = ver >++ self.number = 0. >++ >++ def __lt__(self, other): >++ if self.number == other.number: >++ return self.name < other.name >++ return self.number < other.number >++ >+ @conf >+ def setup_msvc(conf, versiondict): >+ """ >+@@ -125,7 +140,7 @@ def setup_msvc(conf, versiondict): >+ platforms=Utils.to_list(conf.env.MSVC_TARGETS) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms] >+ desired_versions = getattr(Options.options, 'msvc_version', '').split(',') >+ if desired_versions == ['']: >+- desired_versions = conf.env.MSVC_VERSIONS or list(reversed(sorted(versiondict.keys()))) >++ desired_versions = conf.env.MSVC_VERSIONS or list(sorted(versiondict.keys(), key=MSVCVersion, reverse=True)) >+ >+ # Override lazy detection by evaluating after the fact. >+ lazy_detect = getattr(Options.options, 'msvc_lazy', True) >+diff --git third_party/waf/waflib/Tools/python.py third_party/waf/waflib/Tools/python.py >+index fb641e5e20d..a23bd019335 100644 >+--- third_party/waf/waflib/Tools/python.py >++++ third_party/waf/waflib/Tools/python.py >+@@ -315,7 +315,7 @@ def check_python_headers(conf, features='pyembed pyext'): >+ conf.fatal('Could not find the python executable') >+ >+ # so we actually do all this for compatibility reasons and for obtaining pyext_PATTERN below >+- v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split() >++ v = 'prefix SO EXT_SUFFIX LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split() >+ try: >+ lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v]) >+ except RuntimeError: >+@@ -328,7 +328,7 @@ def check_python_headers(conf, features='pyembed pyext'): >+ x = 'MACOSX_DEPLOYMENT_TARGET' >+ if dct[x]: >+ env[x] = conf.environ[x] = str(dct[x]) >+- env.pyext_PATTERN = '%s' + dct['SO'] # not a mistake >++ env.pyext_PATTERN = '%s' + (dct['EXT_SUFFIX'] or dct['SO']) # SO is deprecated in 3.5 and removed in 3.11 >+ >+ >+ # Try to get pythonX.Y-config >+diff --git third_party/waf/waflib/Tools/tex.py third_party/waf/waflib/Tools/tex.py >+index eaf9fdb5802..b4792c3fe87 100644 >+--- third_party/waf/waflib/Tools/tex.py >++++ third_party/waf/waflib/Tools/tex.py >+@@ -90,6 +90,7 @@ class tex(Task.Task): >+ Compiles a tex/latex file. >+ >+ .. inheritance-diagram:: waflib.Tools.tex.latex waflib.Tools.tex.xelatex waflib.Tools.tex.pdflatex >++ :top-classes: waflib.Tools.tex.tex >+ """ >+ >+ bibtex_fun, _ = Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}', shell=False) >+-- >+2.37.3 >+ >diff --git a/net/samba413/pkg-plist.ad_dc b/net/samba413/pkg-plist.ad_dc >index 13dbcc536782..b7c8a91fbba4 100644 >--- a/net/samba413/pkg-plist.ad_dc >+++ b/net/samba413/pkg-plist.ad_dc >@@ -5,7 +5,6 @@ sbin/samba_dnsupdate > sbin/samba_kcc > sbin/samba_spnupdate > sbin/samba_upgradedns >-sbin/samba-gpupdate > include/samba4/dcerpc_server.h > lib/samba4/libdcerpc-server.so > lib/samba4/libdcerpc-server.so.0 >@@ -172,4 +171,3 @@ lib/samba4/private/libscavenge-dns-records-samba4.so > @dir %%DATADIR%%/setup/ad-schema > @dir %%DATADIR%%/setup > @dir %%DATADIR%% >-man/man8/samba-gpupdate.8.gz >diff --git a/net/samba413/pkg-plist.python b/net/samba413/pkg-plist.python >index c931ab22f63e..6de93c2891d0 100644 >--- a/net/samba413/pkg-plist.python >+++ b/net/samba413/pkg-plist.python >@@ -1,5 +1,7 @@ > bin/smbtorture >+sbin/samba-gpupdate > man/man1/smbtorture.1.gz >+man/man8/samba-gpupdate.8.gz > include/samba4/policy.h > lib/samba4/libsamba-policy%%PYTHON_EXT_SUFFIX%%.so > lib/samba4/libsamba-policy%%PYTHON_EXT_SUFFIX%%.so.0 >@@ -258,6 +260,7 @@ lib/samba4/private/libsamba-python%%PYTHON_EXT_SUFFIX%%-samba4.so > %%PYTHON_SITELIBDIR%%/samba/tests/krb5/kdc_base_test.py > %%PYTHON_SITELIBDIR%%/samba/tests/krb5/kdc_tests.py > %%PYTHON_SITELIBDIR%%/samba/tests/krb5/kdc_tgs_tests.py >+%%PYTHON_SITELIBDIR%%/samba/tests/krb5/kpasswd_tests.py > %%PYTHON_SITELIBDIR%%/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py > %%PYTHON_SITELIBDIR%%/samba/tests/krb5/raw_testcase.py > %%PYTHON_SITELIBDIR%%/samba/tests/krb5/rfc4120_constants.py >-- >2.37.3 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 266641
: 236856