From fe3f4e5015dd659673400c86a4ebf009cea26fcc Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 2 Oct 2025 11:48:53 +0000 Subject: [PATCH] Import from CS git --- ...ss-across-krbprincipalname-and-krbca.patch | 106 ++++++++ ...orce-PAC-presence-on-TGT-for-TGS-REQ.patch | 227 ++++++++++++++++++ ...end-test-for-unique-krbcanonicalname.patch | 93 +++++++ SPECS/freeipa.spec | 25 +- 4 files changed, 448 insertions(+), 3 deletions(-) create mode 100644 SOURCES/0060-Enforce-uniqueness-across-krbprincipalname-and-krbca.patch create mode 100644 SOURCES/0061-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ.patch create mode 100644 SOURCES/0062-ipatests-extend-test-for-unique-krbcanonicalname.patch diff --git a/SOURCES/0060-Enforce-uniqueness-across-krbprincipalname-and-krbca.patch b/SOURCES/0060-Enforce-uniqueness-across-krbprincipalname-and-krbca.patch new file mode 100644 index 0000000..cdfac2e --- /dev/null +++ b/SOURCES/0060-Enforce-uniqueness-across-krbprincipalname-and-krbca.patch @@ -0,0 +1,106 @@ +From a37de8c22976a75caf969e232229ff6521ff4936 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 10 Jul 2025 11:44:36 -0400 +Subject: [PATCH] Enforce uniqueness across krbprincipalname and + krbcanonicalname + +This relies on a fix in 389-ds that extends the uniqueness plugin +to be able to compare attributes with different matching syntax. + +This will prevent privilege escalation attacks if one of the +attributes is not set on an entry if it is set elsewhere. + +Signed-off-by: Rob Crittenden +--- + install/share/unique-attributes.ldif | 28 +++++----------------------- + install/updates/10-uniqueness.update | 27 +++++++++++++++++++++++---- + 2 files changed, 28 insertions(+), 27 deletions(-) + +diff --git a/install/share/unique-attributes.ldif b/install/share/unique-attributes.ldif +index 60f2c3470..b28d981b5 100644 +--- a/install/share/unique-attributes.ldif ++++ b/install/share/unique-attributes.ldif +@@ -1,34 +1,16 @@ +-dn: cn=krbPrincipalName uniqueness,cn=plugins,cn=config ++dn: cn=kerberos name uniqueness,cn=plugins,cn=config + changetype: add + objectClass: top + objectClass: nsSlapdPlugin + objectClass: extensibleObject +-cn: krbPrincipalName uniqueness ++cn: kerberos name uniqueness + nsslapd-pluginPath: libattr-unique-plugin + nsslapd-pluginInitfunc: NSUniqueAttr_Init + nsslapd-pluginType: preoperation + nsslapd-pluginEnabled: on +-uniqueness-attribute-name: krbPrincipalName +-nsslapd-plugin-depends-on-type: database +-nsslapd-pluginId: NSUniqueAttr +-nsslapd-pluginVersion: 1.1.0 +-nsslapd-pluginVendor: Fedora Project +-nsslapd-pluginDescription: Enforce unique attribute values +-uniqueness-subtrees: $SUFFIX +-uniqueness-exclude-subtrees: cn=staged users,cn=accounts,cn=provisioning,$SUFFIX +-uniqueness-across-all-subtrees: on +- +-dn: cn=krbCanonicalName uniqueness,cn=plugins,cn=config +-changetype: add +-objectClass: top +-objectClass: nsSlapdPlugin +-objectClass: extensibleObject +-cn: krbCanonicalName uniqueness +-nsslapd-pluginPath: libattr-unique-plugin +-nsslapd-pluginInitfunc: NSUniqueAttr_Init +-nsslapd-pluginType: preoperation +-nsslapd-pluginEnabled: on +-uniqueness-attribute-name: krbCanonicalName ++uniqueness-attribute-name: krbPrincipalName:CaseIgnoreMatch: ++uniqueness-attribute-name: krbPrincipalAlias:CaseIgnoreMatch: ++uniqueness-attribute-name: krbCanonicalName:CaseIgnoreMatch: + nsslapd-plugin-depends-on-type: database + nsslapd-pluginId: NSUniqueAttr + nsslapd-pluginVersion: 1.1.0 +diff --git a/install/updates/10-uniqueness.update b/install/updates/10-uniqueness.update +index fa17911f2..5c5bfd3e0 100644 +--- a/install/updates/10-uniqueness.update ++++ b/install/updates/10-uniqueness.update +@@ -63,13 +63,32 @@ add:uniqueness-subtree-entries-oc: posixAccount + + # krbPrincipalName uniqueness scopes Active/Delete containers + dn: cn=krbPrincipalName uniqueness,cn=plugins,cn=config +-add:uniqueness-exclude-subtrees: cn=staged users,cn=accounts,cn=provisioning,$SUFFIX +-add:uniqueness-across-all-subtrees: on ++deleteentry: cn=krbPrincipalName uniqueness,cn=plugins,cn=config + + # krbCanonicalName uniqueness scopes Active/Delete containers + dn: cn=krbCanonicalName uniqueness,cn=plugins,cn=config +-add:uniqueness-exclude-subtrees: cn=staged users,cn=accounts,cn=provisioning,$SUFFIX +-add:uniqueness-across-all-subtrees: on ++deleteentry: dn: cn=krbCanonicalName uniqueness,cn=plugins,cn=config ++ ++dn: cn=kerberos name uniqueness,cn=plugins,cn=config ++default:objectClass: top ++default:objectClass: nsSlapdPlugin ++default:objectClass: extensibleObject ++default:cn: kerberos name uniqueness ++default:nsslapd-pluginPath: libattr-unique-plugin ++default:nsslapd-pluginInitfunc: NSUniqueAttr_Init ++default:nsslapd-pluginType: preoperation ++default:nsslapd-pluginEnabled: on ++default:uniqueness-attribute-name: krbPrincipalName:CaseIgnoreMatch: ++default:uniqueness-attribute-name: krbPrincipalAlias:CaseIgnoreMatch: ++default:uniqueness-attribute-name: krbCanonicalName:CaseIgnoreMatch: ++default:nsslapd-plugin-depends-on-type: database ++default:nsslapd-pluginId: NSUniqueAttr ++default:nsslapd-pluginVersion: 1.1.0 ++default:nsslapd-pluginVendor: Fedora Project ++default:nsslapd-pluginDescription: Enforce unique attribute values ++default:uniqueness-subtrees: $SUFFIX ++default:uniqueness-exclude-subtrees: cn=staged users,cn=accounts,cn=provisioning,$SUFFIX ++default:uniqueness-across-all-subtrees: on + + # ipaUniqueID uniqueness scopes Active/Delete containers + dn: cn=ipaUniqueID uniqueness,cn=plugins,cn=config +-- +2.50.1 + diff --git a/SOURCES/0061-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ.patch b/SOURCES/0061-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ.patch new file mode 100644 index 0000000..414100c --- /dev/null +++ b/SOURCES/0061-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ.patch @@ -0,0 +1,227 @@ +From 54a9d18c74a887c1949230cc23600317af9a862d Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Fri, 18 Jul 2025 10:26:37 +0200 +Subject: [PATCH] ipa-kdb: enforce PAC presence on TGT for TGS-REQ + +MS-KILE's PA-PAC-REQUEST sequence allows the Kerberos client to request +a TGT without a PAC. At the moment, there is no way to configure the MIT +KDC to reject such request. + +This commit enforces the presence of the PAC when processing TGTs +provided by TGS-REQ. It ensures the server principal of the TGT is the +same as the one in PAC_CLIENT_INFO (i.e. enforces client principal +canonicalization) with integrity check. + +Only one exception is applied: this check is skipped for local TGTs on +domain where the MS-PAC generator is not initialized (i.e. domains where +SID generation was not executed yet). + +Signed-off-by: Julien Rische +--- + daemons/ipa-kdb/ipa_kdb.h | 9 +++ + daemons/ipa-kdb/ipa_kdb_common.c | 18 ++++++ + daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 2 +- + daemons/ipa-kdb/ipa_kdb_mspac.c | 87 ++++++++++++++++++++++++++++ + daemons/ipa-kdb/ipa_kdb_principals.c | 21 +------ + 5 files changed, 116 insertions(+), 21 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 58a0339fc..8fa050995 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -431,6 +431,14 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + const char *test_realm, size_t size, + char **trusted_realm); + ++/* Check the ticket provided in a TGS-REQ. In some situations, the ticket is ++ * expected to contain a PAC. If it is not the case, or if the function is ++ * enable to decode an authorization-data element, it fails. ++ * Any failure should result in the TGS-REQ to be rejected. */ ++krb5_error_code ipadb_enforce_pac(krb5_context kcontext, ++ const krb5_ticket *ticket, ++ const char **status); ++ + /* DELEGATION CHECKS */ + + krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext, +@@ -475,3 +483,4 @@ int ipadb_string_to_sid(const char *str, struct dom_sid *sid); + void alloc_sid(struct dom_sid **sid); + void free_sid(struct dom_sid **sid); + bool dom_sid_check(const struct dom_sid *sid1, const struct dom_sid *sid2, bool exact_check); ++bool ipadb_is_tgs_princ(krb5_context kcontext, krb5_const_principal princ); +diff --git a/daemons/ipa-kdb/ipa_kdb_common.c b/daemons/ipa-kdb/ipa_kdb_common.c +index ae7742a32..fc603cbe2 100644 +--- a/daemons/ipa-kdb/ipa_kdb_common.c ++++ b/daemons/ipa-kdb/ipa_kdb_common.c +@@ -767,3 +767,21 @@ krb5_error_code ipadb_multibase_search(struct ipadb_context *ipactx, + return ipadb_simple_ldap_to_kerr(ret); + } + ++bool ++ipadb_is_tgs_princ(krb5_context kcontext, krb5_const_principal princ) ++{ ++ krb5_data *primary; ++ size_t l_tgs_name; ++ ++ if (2 != krb5_princ_size(kcontext, princ)) ++ return false; ++ ++ primary = krb5_princ_component(kcontext, princ, 0); ++ ++ l_tgs_name = strlen(KRB5_TGS_NAME); ++ ++ if (l_tgs_name != primary->length) ++ return false; ++ ++ return 0 == memcmp(primary->data, KRB5_TGS_NAME, l_tgs_name); ++} +diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +index 2802221c7..aa8de3eda 100644 +--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +@@ -195,7 +195,7 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata, + *lifetime_out = 0; + *renew_lifetime_out = 0; + +- return 0; ++ return ipadb_enforce_pac(context, ticket, status); + } + + krb5_error_code kdcpolicy_ipakdb_initvt(krb5_context context, +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 9723103d8..9a7aedd84 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3346,3 +3346,90 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + + return KRB5_KDB_NOENTRY; + } ++ ++static krb5_error_code ++check_for_pac(krb5_context kcontext, krb5_authdata **authdata, bool *pac_present) ++{ ++ krb5_error_code kerr = ENOENT; ++ size_t i, j; ++ krb5_authdata **ifrel = NULL; ++ ++ for (i = 0; authdata && authdata[i]; ++i) { ++ if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT) { ++ continue; ++ } ++ ++ kerr = krb5_decode_authdata_container(kcontext, ++ KRB5_AUTHDATA_IF_RELEVANT, ++ authdata[i], &ifrel); ++ if (kerr) { ++ goto end; ++ } ++ ++ for (j = 0; ifrel[j]; ++j) { ++ if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC) { ++ break; ++ } ++ } ++ if (ifrel[j]) { ++ break; ++ } ++ ++ krb5_free_authdata(kcontext, ifrel); ++ ifrel = NULL; ++ } ++ ++ *pac_present = ifrel; ++ kerr = 0; ++ ++end: ++ krb5_free_authdata(kcontext, ifrel); ++ return kerr; ++} ++ ++krb5_error_code ++ipadb_enforce_pac(krb5_context kcontext, const krb5_ticket *ticket, ++ const char **status) ++{ ++ struct ipadb_context *ipactx; ++ bool pac_present; ++ krb5_error_code kerr; ++ ++ /* Filter TGTs only */ ++ if (!ipadb_is_tgs_princ(kcontext, ticket->server)) { ++ kerr = 0; ++ goto end; ++ } ++ ++ /* Get IPA context */ ++ ipactx = ipadb_get_context(kcontext); ++ if (!ipactx) { ++ kerr = KRB5_KDB_DBNOTINITED; ++ goto end; ++ } ++ ++ /* If local TGT but PAC generator not initialized, skip PAC enforcement */ ++ if (krb5_realm_compare(kcontext, ipactx->local_tgs, ticket->server) && ++ !ipactx->mspac) ++ { ++ krb5_klog_syslog(LOG_WARNING, "MS-PAC not available. This makes " ++ "FreeIPA vulnerable to privilege escalation exploit " ++ "(CVE-2025-7493). Please generate SIDs to enable PAC " ++ "support."); ++ kerr = 0; ++ goto end; ++ } ++ ++ /* Search for the PAC, fail if it cannot be found */ ++ kerr = check_for_pac(kcontext, ticket->enc_part2->authorization_data, ++ &pac_present); ++ if (kerr) { ++ *status = "PAC_ENFORCEMENT_CANNOT_DECODE_TGT_AUTHDATA"; ++ } else if (!pac_present) { ++ kerr = ENOENT; ++ *status = "PAC_ENFORCEMENT_TGT_WITHOUT_PAC"; ++ } ++ ++end: ++ return kerr; ++} +diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c +index 19998c2a3..a238bde75 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -188,25 +188,6 @@ done: + return ret; + } + +-static bool +-is_tgs_princ(krb5_context kcontext, krb5_const_principal princ) +-{ +- krb5_data *primary; +- size_t l_tgs_name; +- +- if (2 != krb5_princ_size(kcontext, princ)) +- return false; +- +- primary = krb5_princ_component(kcontext, princ, 0); +- +- l_tgs_name = strlen(KRB5_TGS_NAME); +- +- if (l_tgs_name != primary->length) +- return false; +- +- return 0 == memcmp(primary->data, KRB5_TGS_NAME, l_tgs_name); +-} +- + static krb5_error_code + cmp_local_tgs_princ(krb5_context kcontext, const char *local_realm, + krb5_const_principal princ, bool *result) +@@ -2080,7 +2061,7 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, + return kerr; + + /* If TGS principal, some virtual attributes may be added */ +- if (is_tgs_princ(kcontext, (*entry)->princ)) { ++ if (ipadb_is_tgs_princ(kcontext, (*entry)->princ)) { + kerr = cmp_local_tgs_princ(kcontext, ipactx->realm, (*entry)->princ, + &is_local_tgs_princ); + if (kerr) +-- +2.51.0 + diff --git a/SOURCES/0062-ipatests-extend-test-for-unique-krbcanonicalname.patch b/SOURCES/0062-ipatests-extend-test-for-unique-krbcanonicalname.patch new file mode 100644 index 0000000..e351259 --- /dev/null +++ b/SOURCES/0062-ipatests-extend-test-for-unique-krbcanonicalname.patch @@ -0,0 +1,93 @@ +From d57d11974e05f84c0964ca941a6b507419b02211 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 28 Aug 2025 15:31:39 +0200 +Subject: [PATCH] ipatests: extend test for unique krbcanonicalname + +Add a test ensuring that root@REALM cannot be added as +krbcanonicalname + +Add a test for PAC enforcement: +try to access a service using a TGT obtained without PAC. +Should fail as PAC is now enforced. + +Signed-off-by: Florence Blanc-Renaud +--- + ipatests/test_integration/test_commands.py | 44 ++++++++++++++++++++-- + 1 file changed, 40 insertions(+), 4 deletions(-) + +diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py +index 38202c9a3fbc5e91c03a5953a5d9bec3c07117f4..c982c678aae047d5cb505889729bcb5bccbc3c20 100644 +--- a/ipatests/test_integration/test_commands.py ++++ b/ipatests/test_integration/test_commands.py +@@ -2090,7 +2090,7 @@ class TestIPACommandWithoutReplica(IntegrationTest): + hostname = master.hostname + realm = master.domain.realm + principal = f'test/{hostname}@{realm}' +- entry_ldif = textwrap.dedent(""" ++ entry_ldif_template = textwrap.dedent(""" + dn: krbprincipalname={principal},cn=services,cn=accounts,{base_dn} + changetype: add + ipakrbprincipalalias: test/{hostname}@{realm} +@@ -2101,13 +2101,15 @@ class TestIPACommandWithoutReplica(IntegrationTest): + objectclass: krbprincipal + objectclass: krbprincipalaux + objectclass: top +- krbcanonicalname: admin@{realm} ++ krbcanonicalname: {user}@{realm} + managedby: fqdn={hostname},cn=computers,cn=accounts,{base_dn} +- """).format( ++ """) ++ entry_ldif = entry_ldif_template.format( + base_dn=base_dn, + hostname=hostname, + principal=principal, +- realm=realm) ++ realm=realm, ++ user='admin') + tasks.kdestroy_all(master) + master.run_command( + ['kinit', '-kt', '/etc/krb5.keytab', f'host/{hostname}@{realm}']) +@@ -2120,6 +2122,40 @@ class TestIPACommandWithoutReplica(IntegrationTest): + raiseonerr=False) + assert "entry with the same attribute value" in result.stderr_text + ++ # Now try with root@realm instead of admin@realm ++ entry_ldif = entry_ldif_template.format( ++ base_dn=base_dn, ++ hostname=hostname, ++ principal=principal, ++ realm=realm, ++ user='root') ++ args = [ ++ 'ldapmodify', ++ '-Y', ++ 'GSSAPI' ++ ] ++ result = master.run_command(args, stdin_text=entry_ldif, ++ raiseonerr=False) ++ assert "entry with the same attribute value" in result.stderr_text ++ tasks.kdestroy_all(master) ++ ++ def test_no_request_pac(self): ++ # Try to use a TGT obtained without PAC ++ # Should fail as the presence of the PAC when processing TGTs ++ # provided by TGS-REQ is now enforced. ++ hostname = self.master.hostname ++ realm = self.master.domain.realm ++ self.master.run_command([ ++ 'kinit', '-kt', '/etc/krb5.keytab', f'host/{hostname}@{realm}', ++ '--no-request-pac' ++ ]) ++ result = self.master.run_command( ++ ['kvno', f'ldap/{hostname}@{realm}'], ++ raiseonerr=False ++ ) ++ assert result.returncode == 1 ++ assert "PAC_ENFORCEMENT_TGT_WITHOUT_PAC" in result.stderr_text ++ + + class TestIPAautomount(IntegrationTest): + @classmethod +-- +2.51.0 + diff --git a/SPECS/freeipa.spec b/SPECS/freeipa.spec index f3a6709..b575053 100644 --- a/SPECS/freeipa.spec +++ b/SPECS/freeipa.spec @@ -79,7 +79,9 @@ %global selinux_policy_version 3.14.3-107 %else # version supporting LMDB and lib389.cli_ctl.dblib.run_dbscan utility -%global ds_version 2.1.0 +# Allow Uniqueness plugin to search uniqueness +# attributes using custom matching rules +%global ds_version 2.6.1-11 %global selinux_policy_version 38.1.1-1 %endif @@ -218,7 +220,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 14%{?rc_version:.%rc_version}%{?dist}.3 +Release: 14%{?rc_version:.%rc_version}.0.1%{?dist}.5 Summary: The Identity, Policy and Audit system License: GPL-3.0-or-later @@ -301,6 +303,9 @@ Patch0056: 0056-kdb-keep-ipadb_get_connection-from-succeeding-with-n.patch Patch0057: 0057-Set-krbCanonicalName-admin-REALM-on-the-admin-user.patch Patch0058: 0058-ipa-sidgen-fix-memory-leak-in-ipa_sidgen_add_post_op.patch Patch0059: 0059-ipatests-use-sos-report-instead-of-sosreport-command.patch +Patch0060: 0060-Enforce-uniqueness-across-krbprincipalname-and-krbca.patch +Patch0061: 0061-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ.patch +Patch0062: 0062-ipatests-extend-test-for-unique-krbcanonicalname.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -629,6 +634,7 @@ BuildArch: noarch Requires: %{name}-client-common = %{version}-%{release} Requires: httpd >= %{httpd_version} Requires: systemd-units >= %{systemd_version} +Requires: bind >= %{bind_version} %if 0%{?rhel} >= 8 && ! 0%{?eln} Requires: system-logos-ipa >= 80.4 %endif @@ -1103,7 +1109,8 @@ autoreconf -ivf %{enable_server_option} \ %{with_ipatests_option} \ %{with_ipa_join_xml_option} \ - %{linter_options} + %{linter_options} \ + --with-ipaplatform=rhel # run build in default dir # -Onone is workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1398405 @@ -1947,6 +1954,18 @@ fi %endif %changelog +* Tue Sep 30 2025 EL Errata - 4.12.2-14.0.1.5 +- Set IPAPLATFORM=rhel when build on Oracle Linux [Orabug: 29516674] +- Add bind to ipa-server-common Requires [Orabug: 36518596] + +* Thu Sep 11 2025 Florence Blanc-Renaud - 4.12.2-14.5 +- Resolves: RHEL-110068 + EMBARGOED CVE-2025-7493 ipa: Privilege escalation from host to domain admin in FreeIPA + +* Wed Sep 03 2025 Florence Blanc-Renaud - 4.12.2-14.4 +- Resolves: RHEL-110068 + EMBARGOED CVE-2025-7493 ipa: Privilege escalation from host to domain admin in FreeIPA + * Tue Jul 29 2025 Florence Blanc-Renaud - 4.12.2-14.3 - Resolves: RHEL-106165 ipatests: use "sos report" instead of "sosreport" command