diff --git a/SOURCES/0041-Enforce-uniqueness-across-krbprincipalname-and-krbca_rhel#110061.patch b/SOURCES/0041-Enforce-uniqueness-across-krbprincipalname-and-krbca_rhel#110061.patch new file mode 100644 index 0000000..cdfac2e --- /dev/null +++ b/SOURCES/0041-Enforce-uniqueness-across-krbprincipalname-and-krbca_rhel#110061.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/0042-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ_rhel#110061.patch b/SOURCES/0042-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ_rhel#110061.patch new file mode 100644 index 0000000..762c418 --- /dev/null +++ b/SOURCES/0042-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ_rhel#110061.patch @@ -0,0 +1,230 @@ +From 4784cb826f7cfd01471c29cfb51bdf6d34d6d643 Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Tue, 9 Sep 2025 12:45:24 -0300 +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 85cabe142..7bad8c85f 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -434,6 +434,14 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, + # endif + #endif + ++/* 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, +@@ -472,3 +480,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 42e0856d0..eb0b0d129 100644 +--- a/daemons/ipa-kdb/ipa_kdb_common.c ++++ b/daemons/ipa-kdb/ipa_kdb_common.c +@@ -704,3 +704,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 d6d618d1d..a92a9a0ad 100644 +--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +@@ -207,7 +207,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 0964d112a..c4085fca5 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3344,6 +3344,93 @@ 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; ++} ++ + #if KRB5_KDB_DAL_MAJOR_VERSION <= 8 + # ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + krb5_error_code +diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c +index 6ee274053..11e084739 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -183,25 +183,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 ipadb_set_tl_data(krb5_db_entry *entry, + krb5_int16 type, + krb5_ui_2 length, +@@ -1882,7 +1863,7 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, + + #if KRB5_KDB_DAL_MAJOR_VERSION <= 8 + /* 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 = krb5_dbe_set_string(kcontext, *entry, + KRB5_KDB_SK_OPTIONAL_AD_SIGNEDPATH, + "true"); +-- +2.51.0 + diff --git a/SOURCES/0043-ipatests-extend-test-for-unique-krbcanonicalname_rhel#110061.patch b/SOURCES/0043-ipatests-extend-test-for-unique-krbcanonicalname_rhel#110061.patch new file mode 100644 index 0000000..47fb635 --- /dev/null +++ b/SOURCES/0043-ipatests-extend-test-for-unique-krbcanonicalname_rhel#110061.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 +@@ -1563,7 +1563,7 @@ def test_unique_krbcanonicalname(self): + 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} +@@ -1573,13 +1573,15 @@ def test_unique_krbcanonicalname(self): + 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}']) +@@ -1592,6 +1594,40 @@ def test_unique_krbcanonicalname(self): + 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 TestIPACommandWithoutReplica(IntegrationTest): + """ +-- +2.51.0 + diff --git a/SOURCES/0044-ipatests-refactor-krb-unique-tests_rhel#110061.patch b/SOURCES/0044-ipatests-refactor-krb-unique-tests_rhel#110061.patch new file mode 100644 index 0000000..b244913 --- /dev/null +++ b/SOURCES/0044-ipatests-refactor-krb-unique-tests_rhel#110061.patch @@ -0,0 +1,173 @@ +--- a/ipatests/test_integration/test_commands.py 2025-09-17 10:36:00.180673487 -0300 ++++ b/ipatests/test_integration/test_commands.py 2025-09-17 10:37:31.294681273 -0300 +@@ -1554,80 +1554,6 @@ + assert result.returncode == 1 + assert 'cannot be deleted or disabled' in result.stderr_text + +- def test_unique_krbcanonicalname(self): +- """Verify that the uniqueness for krbcanonicalname is working""" +- master = self.master +- +- base_dn = str(master.domain.basedn) +- hostname = master.hostname +- realm = master.domain.realm +- principal = f'test/{hostname}@{realm}' +- entry_ldif_template = textwrap.dedent(""" +- dn: krbprincipalname={principal},cn=services,cn=accounts,{base_dn} +- changetype: add +- ipakrbprincipalalias: test/{hostname}@{realm} +- krbprincipalname: {principal} +- objectclass: ipakrbprincipal +- objectclass: ipaobject +- objectclass: ipaservice +- objectclass: krbprincipal +- objectclass: krbprincipalaux +- objectclass: top +- krbcanonicalname: {user}@{realm} +- managedby: fqdn={hostname},cn=computers,cn=accounts,{base_dn} +- """) +- entry_ldif = entry_ldif_template.format( +- base_dn=base_dn, +- hostname=hostname, +- principal=principal, +- realm=realm, +- user='admin') +- tasks.kdestroy_all(master) +- master.run_command( +- ['kinit', '-kt', '/etc/krb5.keytab', f'host/{hostname}@{realm}']) +- 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 +- +- # 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 TestIPACommandWithoutReplica(IntegrationTest): + """ +@@ -1749,7 +1675,7 @@ + api.bootstrap_with_global_options(context='server') + api.finalize() + api.Backend.ldap2.connect() +- ++ + api.Command["group_add"]("testgroup1", external=True) + api.Command["group_add"]("testgroup2", external=False) + result1 = api.Command["group_show"]("testgroup1", all=True)["result"] # noqa: E501 +@@ -1794,6 +1720,80 @@ + '/tmp/reproducer2_code.py']) + assert "missing attribute" not in result.stdout_text + ++ def test_unique_krbcanonicalname(self): ++ """Verify that the uniqueness for krbcanonicalname is working""" ++ master = self.master ++ ++ base_dn = str(master.domain.basedn) ++ hostname = master.hostname ++ realm = master.domain.realm ++ principal = f'test/{hostname}@{realm}' ++ entry_ldif_template = textwrap.dedent(""" ++ dn: krbprincipalname={principal},cn=services,cn=accounts,{base_dn} ++ changetype: add ++ ipakrbprincipalalias: test/{hostname}@{realm} ++ krbprincipalname: {principal} ++ objectclass: ipakrbprincipal ++ objectclass: ipaobject ++ objectclass: ipaservice ++ objectclass: krbprincipal ++ objectclass: krbprincipalaux ++ objectclass: top ++ krbcanonicalname: {user}@{realm} ++ managedby: fqdn={hostname},cn=computers,cn=accounts,{base_dn} ++ """) ++ entry_ldif = entry_ldif_template.format( ++ base_dn=base_dn, ++ hostname=hostname, ++ principal=principal, ++ realm=realm, ++ user='admin') ++ tasks.kdestroy_all(master) ++ master.run_command( ++ ['kinit', '-kt', '/etc/krb5.keytab', f'host/{hostname}@{realm}']) ++ 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 ++ ++ # 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 diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec index 1cb969d..562cd9c 100644 --- a/SPECS/ipa.spec +++ b/SPECS/ipa.spec @@ -74,7 +74,7 @@ %global python_ldap_version 3.1.0-1 %if 0%{?rhel} < 9 # Bug 1929067 - PKI instance creation failed with new 389-ds-base build -%global ds_version 1.4.3.16-12 +%global ds_version 1.4.3.39-15 %else %global ds_version 2.0.3-3 %endif @@ -190,7 +190,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 18%{?rc_version:.%rc_version}%{?dist} +Release: 20%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPLv3+ @@ -249,6 +249,10 @@ Patch0037: 0037-Replica-CA-installation-ignore-skew-during-initial-replicat Patch0038: 0038-Add-a-check-into-ipa-cert-fix-tool-to-avoid-updating-certs-if-CA-is-close-to-being-expired_rhel#4941.patch Patch0039: 0039-kdb-keeep-ipadb_get_connection-from-succeding-with-null-LDAP-context_rhel#58435.patch Patch0040: 0040-Set-krbCanonicalName-admin-REALM-on-the-admin-user_rhel#89895.patch +Patch0041: 0041-Enforce-uniqueness-across-krbprincipalname-and-krbca_rhel#110061.patch +Patch0042: 0042-ipa-kdb-enforce-PAC-presence-on-TGT-for-TGS-REQ_rhel#110061.patch +Patch0043: 0043-ipatests-extend-test-for-unique-krbcanonicalname_rhel#110061.patch +Patch0044: 0044-ipatests-refactor-krb-unique-tests_rhel#110061.patch %if 0%{?rhel} >= 8 Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch @@ -1763,6 +1767,16 @@ fi %endif %changelog +* Thu Sep 11 2025 Rafael Jeffman - 4.9.13-20 +- Refactor ipatests for unique krbcanonicalname + Resolves: RHEL-110061 + +* Thu Sep 11 2025 Rafael Jeffman - 4.9.13-19 +- Enforce uniqueness across krbprincipalname and krbcanonicalname + ipa-kdb: enforce PAC presence on TGT for TGS-REQ + ipatests: extend test for unique krbcanonicalname + Resolves: RHEL-110061 + * Tue Jun 03 2025 Rafael Jeffman - 4.9.13-18 - Set krbCanonicalName admin@REALM on the admin user Resolves: RHEL-89895