From c2552a1e7a0d98267214b1e19b9106bf940876c9 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 28 Mar 2024 13:46:21 +0000 Subject: [PATCH] import CS ipa-4.9.13-7.module_el8+969+0b4cdf18 --- .gitignore | 2 +- .ipa.metadata | 2 +- ...mba-exception-type-change_rhel#17623.patch | 73 ++ ...in-the-supported-format_rhbz#2150217.patch | 261 ------- ...-HTTP-Referer-header-on-all-requests.patch | 121 +++ ...r-directly-in-cert-find_rhbz#2164349.patch | 242 ------ ...s-for-verifying-Referer-header-in-th.patch | 359 +++++++++ ...drop-in-file-if-missing_rhbz#2215336.patch | 87 --- ...e-fix-replica-agreement_rhbz#2216551.patch | 233 ------ ...-Detect-and-block-Bronze-Bit-attacks.patch | 265 +++++++ ...y-for-ca-less-deployments_rhel#22283.patch | 212 ++++++ ...-avoid-endianness-issue_rhbz#2218293.patch | 52 -- ...est-updates-8-9-release_rhbz#2218847.patch | 173 ----- ...ge-Host-Keytab-permission_rhel#22286.patch | 97 +++ ...defaults-are-set-properly_rhel#21938.patch | 32 + ...dling-of-is_master_host_rhbz#2214638.patch | 85 --- ...ogbuffering-is-set-to-off_rhel#19672.patch | 175 +++++ ...-service-on-acme-client_rhbz#2230256.patch | 39 - ...ted-to-non-existing-idp_rhbz#2224572.patch | 193 ----- ...ical-principal-is-missing_rhel#23630.patch | 45 ++ ...user-from-being-deleted_rhbz#1921181.patch | 169 ----- ...k-during-PAC-verification_rhel#22644.patch | 89 +++ ...e-OTP-last-token-plugin_rhbz#2227783.patch | 114 --- ...Fix-session-cookie-access_rhel#23622.patch | 238 ++++++ ...ed-users-in-sidgen-plugin_rhel#23626.patch | 109 +++ ...tests-fix-test_topology_rhbz#2232351.patch | 58 -- ...m-services-in-sssd.conf_rhbz#2216532.patch | 40 - ...heck-if-PAC-not-available_rhel#22313.patch | 310 ++++++++ ...-otp-auth-type-are-enabled_rhel#4874.patch | 272 +++++++ ...ing-or-returning-messages_rhel#12780.patch | 139 ++++ ...r-replica-update-in-test_dns_locatio.patch | 43 ++ ...17-ipa-kdb-Rework-ipadb_reinit_mspac.patch | 707 ++++++++++++++++++ ...it_for_replication-method_rhel#25708.patch | 34 + ...d-support-for-RSA-OAEP-wrapping-algo.patch | 127 ++++ ...ult-server-archival-retrieval-calls-.patch | 88 +++ ...-as-default-wrapping-algo-when-FIPS-.patch | 98 +++ ...ix-double-free-in-ipadb_reinit_mspac.patch | 29 + SOURCES/freeipa-4.9.12.tar.gz.asc | 16 - SOURCES/freeipa-4.9.13.tar.gz.asc | 16 + SPECS/ipa.spec | 104 ++- 40 files changed, 3768 insertions(+), 1780 deletions(-) create mode 100644 SOURCES/0001-Handle-samba-exception-type-change_rhel#17623.patch delete mode 100644 SOURCES/0001-user-or-group-name-explain-the-supported-format_rhbz#2150217.patch create mode 100644 SOURCES/0002-Check-the-HTTP-Referer-header-on-all-requests.patch delete mode 100644 SOURCES/0002-Use-the-python-cryptography-parser-directly-in-cert-find_rhbz#2164349.patch create mode 100644 SOURCES/0003-Integration-tests-for-verifying-Referer-header-in-th.patch delete mode 100644 SOURCES/0003-Upgrade-add-PKI-drop-in-file-if-missing_rhbz#2215336.patch delete mode 100644 SOURCES/0004-Upgrade-fix-replica-agreement_rhbz#2216551.patch create mode 100644 SOURCES/0004-ipa-kdb-Detect-and-block-Bronze-Bit-attacks.patch create mode 100644 SOURCES/0005-Improve-server-affinity-for-ca-less-deployments_rhel#22283.patch delete mode 100644 SOURCES/0005-OTP-fix-data-type-to-avoid-endianness-issue_rhbz#2218293.patch delete mode 100644 SOURCES/0006-Backport-test-updates-8-9-release_rhbz#2218847.patch create mode 100644 SOURCES/0006-host-update-System-Manage-Host-Keytab-permission_rhel#22286.patch create mode 100644 SOURCES/0007-adtrustinstance-make-sure-NetBIOS-name-defaults-are-set-properly_rhel#21938.patch delete mode 100644 SOURCES/0007-ipa-kdb-fix-error-handling-of-is_master_host_rhbz#2214638.patch create mode 100644 SOURCES/0008-ipatests-Fix-healthcheck-report-when-nsslapd-accesslog-logbuffering-is-set-to-off_rhel#19672.patch delete mode 100644 SOURCES/0008-ipatests-enable-firewall-rule-for-http-service-on-acme-client_rhbz#2230256.patch delete mode 100644 SOURCES/0009-User-plugin-improve-error-related-to-non-existing-idp_rhbz#2224572.patch create mode 100644 SOURCES/0009-kdb-PAC-generator-do-not-fail-if-canonical-principal-is-missing_rhel#23630.patch delete mode 100644 SOURCES/0010-Prevent-admin-user-from-being-deleted_rhbz#1921181.patch create mode 100644 SOURCES/0010-ipa-kdb-Fix-memory-leak-during-PAC-verification_rhel#22644.patch delete mode 100644 SOURCES/0011-Fix-memory-leak-in-the-OTP-last-token-plugin_rhbz#2227783.patch create mode 100644 SOURCES/0011-Fix-session-cookie-access_rhel#23622.patch create mode 100644 SOURCES/0012-Do-not-ignore-staged-users-in-sidgen-plugin_rhel#23626.patch delete mode 100644 SOURCES/0012-ipatests-fix-test_topology_rhbz#2232351.patch delete mode 100644 SOURCES/0013-Installer-activate-nss-and-pam-services-in-sssd.conf_rhbz#2216532.patch create mode 100644 SOURCES/0013-ipa-kdb-Disable-Bronze-Bit-check-if-PAC-not-available_rhel#22313.patch create mode 100644 SOURCES/0014-krb5kdc-Fix-start-when-pkinit-and-otp-auth-type-are-enabled_rhel#4874.patch create mode 100644 SOURCES/0015-hbactest-was-not-collecting-or-returning-messages_rhel#12780.patch create mode 100644 SOURCES/0016-ipatests-wait-for-replica-update-in-test_dns_locatio.patch create mode 100644 SOURCES/0017-ipa-kdb-Rework-ipadb_reinit_mspac.patch create mode 100644 SOURCES/0018-ipatests-fix-tasks-wait_for_replication-method_rhel#25708.patch create mode 100644 SOURCES/0019-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch create mode 100644 SOURCES/0020-Vault-improve-vault-server-archival-retrieval-calls-.patch create mode 100644 SOURCES/0021-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch create mode 100644 SOURCES/0022-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch delete mode 100644 SOURCES/freeipa-4.9.12.tar.gz.asc create mode 100644 SOURCES/freeipa-4.9.13.tar.gz.asc diff --git a/.gitignore b/.gitignore index 5471ecd..dbce2de 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/freeipa-4.9.12.tar.gz +SOURCES/freeipa-4.9.13.tar.gz diff --git a/.ipa.metadata b/.ipa.metadata index de73ab5..ee9bea0 100644 --- a/.ipa.metadata +++ b/.ipa.metadata @@ -1 +1 @@ -ea6c8a209748b4ad8d07da556f705a366b3dd6c1 SOURCES/freeipa-4.9.12.tar.gz +da1bb0220894d8dc06afb98dcf087fea38076a79 SOURCES/freeipa-4.9.13.tar.gz diff --git a/SOURCES/0001-Handle-samba-exception-type-change_rhel#17623.patch b/SOURCES/0001-Handle-samba-exception-type-change_rhel#17623.patch new file mode 100644 index 0000000..b36187f --- /dev/null +++ b/SOURCES/0001-Handle-samba-exception-type-change_rhel#17623.patch @@ -0,0 +1,73 @@ +From 06b4c61b4484efe2093501caf21b03f1fc14093b Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 19 Oct 2023 12:47:03 +0200 +Subject: [PATCH] group-add-member fails with an external member + +The command ipa group-add-member --external aduser@addomain.test +fails with an internal error when used with samba 4.19. + +The command internally calls samba.security.dom_sid(sid) which +used to raise a TypeError but now raises a ValueError +(commit 9abdd67 on https://github.com/samba-team/samba). + +IPA source code needs to handle properly both exception types. + +Fixes: https://pagure.io/freeipa/issue/9466 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/dcerpc.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index c1db2f9a499..ee0a229d1f0 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -303,7 +303,7 @@ def get_domain_by_sid(self, sid, exact_match=False): + # Parse sid string to see if it is really in a SID format + try: + test_sid = security.dom_sid(sid) +- except TypeError: ++ except (TypeError, ValueError): + raise errors.ValidationError(name='sid', + error=_('SID is not valid')) + +From aa3397378acf1a03fc8bbe34b9fae33e84588b34 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 20 Oct 2023 10:20:57 +0200 +Subject: [PATCH] Handle samba changes in samba.security.dom_sid() + +samba.security.dom_sid() in 4.19 now raises ValueError instead of +TypeError. Fix the expected exception. + +Related: https://pagure.io/freeipa/issue/9466 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +--- + ipaserver/dcerpc.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index ee0a229d1f0..3e4c71d9976 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -97,7 +97,7 @@ + def is_sid_valid(sid): + try: + security.dom_sid(sid) +- except TypeError: ++ except (TypeError, ValueError): + return False + else: + return True +@@ -457,7 +457,7 @@ def get_trusted_domain_object_sid(self, object_name, + try: + test_sid = security.dom_sid(sid) + return unicode(test_sid) +- except TypeError: ++ except (TypeError, ValueError): + raise errors.ValidationError(name=_('trusted domain object'), + error=_('Trusted domain did not ' + 'return a valid SID for ' diff --git a/SOURCES/0001-user-or-group-name-explain-the-supported-format_rhbz#2150217.patch b/SOURCES/0001-user-or-group-name-explain-the-supported-format_rhbz#2150217.patch deleted file mode 100644 index 8bad0c6..0000000 --- a/SOURCES/0001-user-or-group-name-explain-the-supported-format_rhbz#2150217.patch +++ /dev/null @@ -1,261 +0,0 @@ -From f42a106e84c1fd609350da2540289ce945a7ecbd Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Thu, 11 May 2023 10:53:58 +0200 -Subject: [PATCH] user or group name: explain the supported format - -The commands ipa user-add or ipa group-add validate the -format of the user/group name and display the following -message when it does not conform to the expectations: -invalid 'login': may only include letters, numbers, _, -, . and $ - -The format is more complex, for instance '1234567' is an invalid -user name but the failure is inconsistent with the error message. -Modify the error message to point to ipa help user/group and add -more details in the help message. - -Same change for idoverrideuser and idoverridegroup: -The user/group name must follow these rules: -- cannot contain only numbers -- must start with a letter, a number, _ or . -- may contain letters, numbers, _, ., or - -- may end with a letter, a number, _, ., - or $ - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2150217 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rafael Guterres Jeffman -Reviewed-By: Alexander Bokovoy -Reviewed-By: Rob Crittenden ---- - ipalib/constants.py | 5 +++++ - ipaserver/plugins/baseuser.py | 2 +- - ipaserver/plugins/group.py | 10 ++++++++-- - ipaserver/plugins/idviews.py | 5 +++-- - ipaserver/plugins/stageuser.py | 6 ++++++ - ipaserver/plugins/user.py | 6 ++++++ - ipatests/test_xmlrpc/test_group_plugin.py | 5 +++-- - ipatests/test_xmlrpc/test_stageuser_plugin.py | 3 ++- - ipatests/test_xmlrpc/test_user_plugin.py | 7 ++++--- - 9 files changed, 38 insertions(+), 11 deletions(-) - -diff --git a/ipalib/constants.py b/ipalib/constants.py -index 4b759a573..104419bc2 100644 ---- a/ipalib/constants.py -+++ b/ipalib/constants.py -@@ -319,6 +319,11 @@ MAXHOSTFQDNLEN = 253 - PATTERN_GROUPUSER_NAME = ( - '(?!^[0-9]+$)^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*[a-zA-Z0-9_.$-]?$' - ) -+ERRMSG_GROUPUSER_NAME = ( -+ 'may only include letters, numbers, _, -, . and $' -+ ', refer to \'ipa help {}\' for complete format ' -+ 'description' -+) - - # Kerberos Anonymous principal name - ANON_USER = 'WELLKNOWN/ANONYMOUS' -diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py -index 684a65242..bae6c54ff 100644 ---- a/ipaserver/plugins/baseuser.py -+++ b/ipaserver/plugins/baseuser.py -@@ -211,7 +211,7 @@ class baseuser(LDAPObject): - takes_params = ( - Str('uid', - pattern=constants.PATTERN_GROUPUSER_NAME, -- pattern_errmsg='may only include letters, numbers, _, -, . and $', -+ pattern_errmsg=constants.ERRMSG_GROUPUSER_NAME.format('user'), - maxlength=255, - cli_name='login', - label=_('User login'), -diff --git a/ipaserver/plugins/group.py b/ipaserver/plugins/group.py -index afdad93c1..0333ed622 100644 ---- a/ipaserver/plugins/group.py -+++ b/ipaserver/plugins/group.py -@@ -24,7 +24,7 @@ import logging - - from ipalib import api - from ipalib import Int, Str, Flag --from ipalib.constants import PATTERN_GROUPUSER_NAME -+from ipalib.constants import PATTERN_GROUPUSER_NAME, ERRMSG_GROUPUSER_NAME - from ipalib.plugable import Registry - from .baseldap import ( - add_external_post_callback, -@@ -70,6 +70,12 @@ converted to non-POSIX groups. - - Every group must have a description. - -+The group name must follow these rules: -+- cannot contain only numbers -+- must start with a letter, a number, _ or . -+- may contain letters, numbers, _, ., or - -+- may end with a letter, a number, _, ., - or $ -+ - POSIX groups must have a Group ID (GID) number. Changing a GID is - supported but can have an impact on your file permissions. It is not necessary - to supply a GID when creating a group. IPA will generate one automatically -@@ -330,7 +336,7 @@ class group(LDAPObject): - takes_params = ( - Str('cn', - pattern=PATTERN_GROUPUSER_NAME, -- pattern_errmsg='may only include letters, numbers, _, -, . and $', -+ pattern_errmsg=ERRMSG_GROUPUSER_NAME.format('group'), - maxlength=255, - cli_name='group_name', - label=_('Group name'), -diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py -index 4f4b3a2f7..6a16884cf 100644 ---- a/ipaserver/plugins/idviews.py -+++ b/ipaserver/plugins/idviews.py -@@ -37,6 +37,7 @@ from ipalib.constants import ( - IPA_ANCHOR_PREFIX, - SID_ANCHOR_PREFIX, - PATTERN_GROUPUSER_NAME, -+ ERRMSG_GROUPUSER_NAME - ) - from ipalib.plugable import Registry - from ipalib.util import (normalize_sshpubkey, validate_sshpubkey, -@@ -1025,7 +1026,7 @@ class idoverrideuser(baseidoverride): - takes_params = baseidoverride.takes_params + ( - Str('uid?', - pattern=PATTERN_GROUPUSER_NAME, -- pattern_errmsg='may only include letters, numbers, _, -, . and $', -+ pattern_errmsg=ERRMSG_GROUPUSER_NAME.format('user'), - maxlength=255, - cli_name='login', - label=_('User login'), -@@ -1128,7 +1129,7 @@ class idoverridegroup(baseidoverride): - takes_params = baseidoverride.takes_params + ( - Str('cn?', - pattern=PATTERN_GROUPUSER_NAME, -- pattern_errmsg='may only include letters, numbers, _, -, . and $', -+ pattern_errmsg=ERRMSG_GROUPUSER_NAME.format('group'), - maxlength=255, - cli_name='group_name', - label=_('Group name'), -diff --git a/ipaserver/plugins/stageuser.py b/ipaserver/plugins/stageuser.py -index 760dff7ab..51438a83a 100644 ---- a/ipaserver/plugins/stageuser.py -+++ b/ipaserver/plugins/stageuser.py -@@ -94,6 +94,12 @@ usernames that start with a digit or usernames that exceed a certain length - may cause problems for some UNIX systems. - Use 'ipa config-mod' to change the username format allowed by IPA tools. - -+The user name must follow these rules: -+- cannot contain only numbers -+- must start with a letter, a number, _ or . -+- may contain letters, numbers, _, ., or - -+- may end with a letter, a number, _, ., - or $ -+ - - EXAMPLES: - -diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py -index fa8a67d3d..643b44f14 100644 ---- a/ipaserver/plugins/user.py -+++ b/ipaserver/plugins/user.py -@@ -88,6 +88,12 @@ usernames that start with a digit or usernames that exceed a certain length - may cause problems for some UNIX systems. - Use 'ipa config-mod' to change the username format allowed by IPA tools. - -+The user name must follow these rules: -+- cannot contain only numbers -+- must start with a letter, a number, _ or . -+- may contain letters, numbers, _, ., or - -+- may end with a letter, a number, _, ., - or $ -+ - Disabling a user account prevents that user from obtaining new Kerberos - credentials. It does not invalidate any credentials that have already - been issued. -diff --git a/ipatests/test_xmlrpc/test_group_plugin.py b/ipatests/test_xmlrpc/test_group_plugin.py -index f9a0e2cfe..27bc21fbc 100644 ---- a/ipatests/test_xmlrpc/test_group_plugin.py -+++ b/ipatests/test_xmlrpc/test_group_plugin.py -@@ -25,6 +25,7 @@ Test the `ipaserver/plugins/group.py` module. - import pytest - - from ipalib import errors -+from ipalib.constants import ERRMSG_GROUPUSER_NAME - from ipatests.test_xmlrpc import objectclasses - from ipatests.test_xmlrpc.xmlrpc_test import ( - fuzzy_digits, fuzzy_uuid, fuzzy_set_ci, -@@ -169,7 +170,7 @@ class TestGroup(XMLRPC_test): - ) - with raises_exact(errors.ValidationError( - name='group_name', -- error=u'may only include letters, numbers, _, -, . and $')): -+ error=ERRMSG_GROUPUSER_NAME.format('group'))): - command() - - def test_create_with_name_starting_with_numeric(self): -@@ -188,7 +189,7 @@ class TestGroup(XMLRPC_test): - ) - with raises_exact(errors.ValidationError( - name='group_name', -- error=u'may only include letters, numbers, _, -, . and $', -+ error=ERRMSG_GROUPUSER_NAME.format('group'), - )): - testgroup.create() - -diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py -index fd146876c..bd877aa94 100644 ---- a/ipatests/test_xmlrpc/test_stageuser_plugin.py -+++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py -@@ -12,6 +12,7 @@ import six - - from collections import OrderedDict - from ipalib import api, errors -+from ipalib.constants import ERRMSG_GROUPUSER_NAME - from ipaplatform.constants import constants as platformconstants - - from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test, raises_exact -@@ -357,7 +358,7 @@ class TestCreateInvalidAttributes(XMLRPC_test): - command = invalid.make_create_command() - with raises_exact(errors.ValidationError( - name='login', -- error=u"may only include letters, numbers, _, -, . and $")): -+ error=ERRMSG_GROUPUSER_NAME.format('user'))): - command() - - def test_create_long_uid(self): -diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py -index c156a8793..eadfe6a65 100644 ---- a/ipatests/test_xmlrpc/test_user_plugin.py -+++ b/ipatests/test_xmlrpc/test_user_plugin.py -@@ -31,6 +31,7 @@ import ldap - import re - - from ipalib import api, errors -+from ipalib.constants import ERRMSG_GROUPUSER_NAME - from ipaplatform.constants import constants as platformconstants - from ipapython import ipautil - from ipatests.test_xmlrpc import objectclasses -@@ -502,7 +503,7 @@ class TestUpdate(XMLRPC_test): - ) - with raises_exact(errors.ValidationError( - name='rename', -- error=u'may only include letters, numbers, _, -, . and $')): -+ error=ERRMSG_GROUPUSER_NAME.format('user'))): - command() - - def test_add_radius_username(self, user): -@@ -556,7 +557,7 @@ class TestCreate(XMLRPC_test): - command = testuser.make_create_command() - with raises_exact(errors.ValidationError( - name=u'login', -- error=u'may only include letters, numbers, _, -, . and $')): -+ error=ERRMSG_GROUPUSER_NAME.format('user'))): - command() - - def test_create_with_too_long_login(self): -@@ -730,7 +731,7 @@ class TestCreate(XMLRPC_test): - ) - with raises_exact(errors.ValidationError( - name=u'login', -- error=u'may only include letters, numbers, _, -, . and $', -+ error=ERRMSG_GROUPUSER_NAME.format('user'), - )): - testuser.create() - --- -2.40.1 - diff --git a/SOURCES/0002-Check-the-HTTP-Referer-header-on-all-requests.patch b/SOURCES/0002-Check-the-HTTP-Referer-header-on-all-requests.patch new file mode 100644 index 0000000..cf512eb --- /dev/null +++ b/SOURCES/0002-Check-the-HTTP-Referer-header-on-all-requests.patch @@ -0,0 +1,121 @@ +From ae006b436cfb4ccee5972cf1db0a309fcd80e669 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Fri, 6 Oct 2023 20:16:29 +0000 +Subject: [PATCH] Check the HTTP Referer header on all requests + +The referer was only checked in WSGIExecutioner classes: + + - jsonserver + - KerberosWSGIExecutioner + - xmlserver + - jsonserver_kerb + +This left /i18n_messages, /session/login_kerberos, +/session/login_x509, /session/login_password, +/session/change_password and /session/sync_token unprotected +against CSRF attacks. + +CVE-2023-5455 + +Signed-off-by: Rob Crittenden +--- + ipaserver/rpcserver.py | 34 +++++++++++++++++++++++++++++++--- + 1 file changed, 31 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 4e8a08b66..3555014ca 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -156,6 +156,19 @@ _success_template = """ + """ + + class HTTP_Status(plugable.Plugin): ++ def check_referer(self, environ): ++ if "HTTP_REFERER" not in environ: ++ logger.error("Rejecting request with missing Referer") ++ return False ++ if (not environ["HTTP_REFERER"].startswith( ++ "https://%s/ipa" % self.api.env.host) ++ and not self.env.in_tree): ++ logger.error("Rejecting request with bad Referer %s", ++ environ["HTTP_REFERER"]) ++ return False ++ logger.debug("Valid Referer %s", environ["HTTP_REFERER"]) ++ return True ++ + def not_found(self, environ, start_response, url, message): + """ + Return a 404 Not Found error. +@@ -331,9 +344,6 @@ class wsgi_dispatch(Executioner, HTTP_Status): + self.__apps[key] = app + + +- +- +- + class WSGIExecutioner(Executioner): + """ + Base class for execution backends with a WSGI application interface. +@@ -897,6 +907,9 @@ class jsonserver_session(jsonserver, KerberosSession): + + logger.debug('WSGI jsonserver_session.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Redirect to login if no Kerberos credentials + ccache_name = self.get_environ_creds(environ) + if ccache_name is None: +@@ -949,6 +962,9 @@ class KerberosLogin(Backend, KerberosSession): + def __call__(self, environ, start_response): + logger.debug('WSGI KerberosLogin.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Redirect to login if no Kerberos credentials + user_ccache_name = self.get_environ_creds(environ) + if user_ccache_name is None: +@@ -967,6 +983,9 @@ class login_x509(KerberosLogin): + def __call__(self, environ, start_response): + logger.debug('WSGI login_x509.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + if 'KRB5CCNAME' not in environ: + return self.unauthorized( + environ, start_response, 'KRB5CCNAME not set', +@@ -1015,6 +1034,9 @@ class login_password(Backend, KerberosSession): + + logger.debug('WSGI login_password.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Get the user and password parameters from the request + content_type = environ.get('CONTENT_TYPE', '').lower() + if not content_type.startswith('application/x-www-form-urlencoded'): +@@ -1147,6 +1169,9 @@ class change_password(Backend, HTTP_Status): + def __call__(self, environ, start_response): + logger.info('WSGI change_password.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Get the user and password parameters from the request + content_type = environ.get('CONTENT_TYPE', '').lower() + if not content_type.startswith('application/x-www-form-urlencoded'): +@@ -1364,6 +1389,9 @@ class xmlserver_session(xmlserver, KerberosSession): + + logger.debug('WSGI xmlserver_session.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + ccache_name = environ.get('KRB5CCNAME') + + # Redirect to /ipa/xml if no Kerberos credentials +-- +2.41.0 + diff --git a/SOURCES/0002-Use-the-python-cryptography-parser-directly-in-cert-find_rhbz#2164349.patch b/SOURCES/0002-Use-the-python-cryptography-parser-directly-in-cert-find_rhbz#2164349.patch deleted file mode 100644 index 7fc5737..0000000 --- a/SOURCES/0002-Use-the-python-cryptography-parser-directly-in-cert-find_rhbz#2164349.patch +++ /dev/null @@ -1,242 +0,0 @@ -From 9fe30f21c987bdccf80ef5f6d645fdc59b393bdb Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Jun 16 2023 19:09:52 +0000 -Subject: Revert "Use the OpenSSL certificate parser in cert-find" - - -This reverts commit 191880bc9f77c3e8a3cecc82e6eea33ab5ad03e4. - -The problem isn't with python-cryptography, it is with the -IPACertificate class which does way more work on a certificate -than is necessary in cert-find. - -Related: https://pagure.io/freeipa/issue/9331 -Reviewed-By: Florence Blanc-Renaud - ---- - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index f3380b4..2b18963 100755 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -390,7 +390,6 @@ BuildRequires: python3-pylint - BuildRequires: python3-pytest-multihost - BuildRequires: python3-pytest-sourceorder - BuildRequires: python3-qrcode-core >= 5.0.0 --BuildRequires: python3-pyOpenSSL - BuildRequires: python3-samba - BuildRequires: python3-six - BuildRequires: python3-sss -@@ -862,7 +861,6 @@ Requires: python3-netifaces >= 0.10.4 - Requires: python3-pyasn1 >= 0.3.2-2 - Requires: python3-pyasn1-modules >= 0.3.2-2 - Requires: python3-pyusb --Requires: python3-pyOpenSSL - Requires: python3-qrcode-core >= 5.0.0 - Requires: python3-requests - Requires: python3-six -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index cec3d93..88c6b62 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -30,7 +30,6 @@ import cryptography.x509 - from cryptography.hazmat.primitives import hashes, serialization - from dns import resolver, reversename - import six --import sys - - from ipalib import Command, Str, Int, Flag, StrEnum - from ipalib import api -@@ -1623,19 +1622,7 @@ class cert_find(Search, CertMethod): - ) - - def _get_cert_key(self, cert): -- # for cert-find with a certificate value -- if isinstance(cert, x509.IPACertificate): -- return (DN(cert.issuer), cert.serial_number) -- -- issuer = [] -- for oid, value in cert.get_issuer().get_components(): -- issuer.append( -- '{}={}'.format(oid.decode('utf-8'), value.decode('utf-8')) -- ) -- issuer = ','.join(issuer) -- # Use this to flip from OpenSSL reverse to X500 ordering -- issuer = DN(issuer).x500_text() -- return (DN(issuer), cert.get_serial_number()) -+ return (DN(cert.issuer), cert.serial_number) - - def _cert_search(self, pkey_only, **options): - result = collections.OrderedDict() -@@ -1755,11 +1742,6 @@ class cert_find(Search, CertMethod): - return result, False, complete - - def _ldap_search(self, all, pkey_only, no_members, **options): -- # defer import of the OpenSSL module to not affect the requests -- # module which will use pyopenssl if this is available. -- if sys.modules.get('OpenSSL.SSL', False) is None: -- del sys.modules["OpenSSL.SSL"] -- import OpenSSL.crypto - ldap = self.api.Backend.ldap2 - - filters = [] -@@ -1818,14 +1800,12 @@ class cert_find(Search, CertMethod): - ca_enabled = getattr(context, 'ca_enabled') - for entry in entries: - for attr in ('usercertificate', 'usercertificate;binary'): -- for der in entry.raw.get(attr, []): -- cert = OpenSSL.crypto.load_certificate( -- OpenSSL.crypto.FILETYPE_ASN1, der) -+ for cert in entry.get(attr, []): - cert_key = self._get_cert_key(cert) - try: - obj = result[cert_key] - except KeyError: -- obj = {'serial_number': cert.get_serial_number()} -+ obj = {'serial_number': cert.serial_number} - if not pkey_only and (all or not ca_enabled): - # Retrieving certificate details is now deferred - # until after all certificates are collected. - -From 3b1dbcdba2994bf57908f530913998e9ab888e4c Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Jun 16 2023 19:09:52 +0000 -Subject: Revert "cert_find: fix call with --all" - - -This reverts commit 1f30cc65276a532e7288217f216b72a2b0628c8f. - -The problem isn't with python-cryptography, it is with the -IPACertificate class which does way more work on a certificate -than is necessary in cert-find. - -Related: https://pagure.io/freeipa/issue/9331 -Reviewed-By: Florence Blanc-Renaud - ---- - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 88c6b62..ba37525 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1812,7 +1812,6 @@ class cert_find(Search, CertMethod): - # For the case of CA-less we need to keep - # the certificate because getting it again later - # would require unnecessary LDAP searches. -- cert = cert.to_cryptography() - obj['certificate'] = ( - base64.b64encode( - cert.public_bytes(x509.Encoding.DER)) - -From d00fd3398c32beb2c3e72f4878c87f9d2c0e833d Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Jun 16 2023 19:09:52 +0000 -Subject: Use the python-cryptography parser directly in cert-find - - -cert-find is a rather complex beast because it not only -looks for certificates in the optional CA but within the -IPA LDAP database as well. It has a process to deduplicate -the certificates since any PKI issued certificates will -also be associated with an IPA record. - -In order to obtain the data to deduplicate the certificates -the cert from LDAP must be parser for issuer and serial number. -ipaldap has automation to determine the datatype of an -attribute and will use the ipalib.x509 IPACertificate class to -decode a certificate automatically if you access -entry['usercertificate']. - -The downside is that this is comparatively slow. Here is the -parse time in microseconds: - -cryptography 0.0081 -OpenSSL.crypto 0.2271 -ipalib.x509 2.6814 - -Since only issuer and subject are required there is no need to -make the expensive IPACertificate call. - -The IPACertificate parsing time is fine if you're parsing one -certificate but if the LDAP search returns a lot of certificates, -say in the thousands, then those microseconds add up quickly. -In testing it took ~17 seconds to parse 5k certificates (excluding -transmission overhead, etc). - -cert-find when there are a lot of certificates has been -historically slow. It isn't related to the CA which returns -large sets (well, 5k anyway) in a second or two. It was the -LDAP comparision adding tens of seconds to the runtime. - -When searching with the default sizelimit of 100 the time is -~10s without this patch. With it the time is 1.5s. - -CLI times from before and after searching for all certs: - -original: - -------------------------------- -Number of entries returned 5038 -------------------------------- -real 0m15.507s -user 0m0.828s -sys 0m0.241s - -using cryptography: - -real 0m4.037s -user 0m0.816s -sys 0m0.193s - -Fixes: https://pagure.io/freeipa/issue/9331 - -Signed-off-by: Rob Crittenden -Reviewed-By: Florence Blanc-Renaud - ---- - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index ba37525..619be83 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1800,7 +1800,8 @@ class cert_find(Search, CertMethod): - ca_enabled = getattr(context, 'ca_enabled') - for entry in entries: - for attr in ('usercertificate', 'usercertificate;binary'): -- for cert in entry.get(attr, []): -+ for der in entry.raw.get(attr, []): -+ cert = cryptography.x509.load_der_x509_certificate(der) - cert_key = self._get_cert_key(cert) - try: - obj = result[cert_key] -diff --git a/ipatests/test_xmlrpc/test_cert_plugin.py b/ipatests/test_xmlrpc/test_cert_plugin.py -index 433cebc..583c67f 100644 ---- a/ipatests/test_xmlrpc/test_cert_plugin.py -+++ b/ipatests/test_xmlrpc/test_cert_plugin.py -@@ -254,6 +254,16 @@ class test_cert(BaseCert): - result = _emails_are_valid(email_addrs, []) - assert not result - -+ def test_00012_cert_find_all(self): -+ """ -+ Test that cert-find --all returns successfully. -+ -+ We don't know how many we'll get but there should be at least 10 -+ by default. -+ """ -+ res = api.Command['cert_find'](all=True) -+ assert 'count' in res and res['count'] >= 10 -+ - def test_99999_cleanup(self): - """ - Clean up cert test data -@@ -283,7 +293,7 @@ class test_cert_find(XMLRPC_test): - - short = api.env.host.split('.', maxsplit=1)[0] - -- def test_0001_find_all(self): -+ def test_0001_find_all_certs(self): - """ - Search for all certificates. - - diff --git a/SOURCES/0003-Integration-tests-for-verifying-Referer-header-in-th.patch b/SOURCES/0003-Integration-tests-for-verifying-Referer-header-in-th.patch new file mode 100644 index 0000000..cbe9eb7 --- /dev/null +++ b/SOURCES/0003-Integration-tests-for-verifying-Referer-header-in-th.patch @@ -0,0 +1,359 @@ +From f1f8b16def3e809f5773bb8aa40aefb21699347b Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 12 Oct 2023 20:34:01 +0000 +Subject: [PATCH] Integration tests for verifying Referer header in the UI + +Validate that the change_password and login_password endpoints +verify the HTTP Referer header. There is some overlap in the +tests: belt and suspenders. + +All endpoints except session/login_x509 are covered, sometimes +having to rely on expected bad results (see the i18n endpoint). + +session/login_x509 is not tested yet as it requires significant +additional setup in order to associate a user certificate with +a user entry, etc. + +This can be manually verified by modifying /etc/httpd/conf.d/ipa.conf +and adding: + +Satisfy Any +Require all granted + +Then comment out Auth and SSLVerify, etc. and restart httpd. + +With a valid Referer will fail with a 401 and log that there is no +KRB5CCNAME. This comes after the referer check. + +With an invalid Referer it will fail with a 400 Bad Request as +expected. + +CVE-2023-5455 + +Signed-off-by: Rob Crittenden +--- + ipatests/test_ipaserver/httptest.py | 7 +- + ipatests/test_ipaserver/test_changepw.py | 12 +- + .../test_ipaserver/test_login_password.py | 88 ++++++++++++ + ipatests/test_ipaserver/test_referer.py | 136 ++++++++++++++++++ + ipatests/util.py | 4 +- + 5 files changed, 242 insertions(+), 5 deletions(-) + create mode 100644 ipatests/test_ipaserver/test_login_password.py + create mode 100644 ipatests/test_ipaserver/test_referer.py + +diff --git a/ipatests/test_ipaserver/httptest.py b/ipatests/test_ipaserver/httptest.py +index 6cd034a71..8924798fc 100644 +--- a/ipatests/test_ipaserver/httptest.py ++++ b/ipatests/test_ipaserver/httptest.py +@@ -36,7 +36,7 @@ class Unauthorized_HTTP_test: + content_type = 'application/x-www-form-urlencoded' + accept_language = 'en-us' + +- def send_request(self, method='POST', params=None): ++ def send_request(self, method='POST', params=None, host=None): + """ + Send a request to HTTP server + +@@ -45,7 +45,10 @@ class Unauthorized_HTTP_test: + if params is not None: + if self.content_type == 'application/x-www-form-urlencoded': + params = urllib.parse.urlencode(params, True) +- url = 'https://' + self.host + self.app_uri ++ if host: ++ url = 'https://' + host + self.app_uri ++ else: ++ url = 'https://' + self.host + self.app_uri + + headers = {'Content-Type': self.content_type, + 'Accept-Language': self.accept_language, +diff --git a/ipatests/test_ipaserver/test_changepw.py b/ipatests/test_ipaserver/test_changepw.py +index c3a47ab26..df38ddb3d 100644 +--- a/ipatests/test_ipaserver/test_changepw.py ++++ b/ipatests/test_ipaserver/test_changepw.py +@@ -53,10 +53,11 @@ class test_changepw(XMLRPC_test, Unauthorized_HTTP_test): + + request.addfinalizer(fin) + +- def _changepw(self, user, old_password, new_password): ++ def _changepw(self, user, old_password, new_password, host=None): + return self.send_request(params={'user': str(user), + 'old_password' : str(old_password), + 'new_password' : str(new_password)}, ++ host=host + ) + + def _checkpw(self, user, password): +@@ -89,6 +90,15 @@ class test_changepw(XMLRPC_test, Unauthorized_HTTP_test): + # make sure that password is NOT changed + self._checkpw(testuser, old_password) + ++ def test_invalid_referer(self): ++ response = self._changepw(testuser, old_password, new_password, ++ 'attacker.test') ++ ++ assert_equal(response.status, 400) ++ ++ # make sure that password is NOT changed ++ self._checkpw(testuser, old_password) ++ + def test_pwpolicy_error(self): + response = self._changepw(testuser, old_password, '1') + +diff --git a/ipatests/test_ipaserver/test_login_password.py b/ipatests/test_ipaserver/test_login_password.py +new file mode 100644 +index 000000000..9425cb797 +--- /dev/null ++++ b/ipatests/test_ipaserver/test_login_password.py +@@ -0,0 +1,88 @@ ++# Copyright (C) 2023 Red Hat ++# see file 'COPYING' for use and warranty information ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import os ++import pytest ++import uuid ++ ++from ipatests.test_ipaserver.httptest import Unauthorized_HTTP_test ++from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test ++from ipatests.util import assert_equal ++from ipalib import api, errors ++from ipapython.ipautil import run ++ ++testuser = u'tuser' ++password = u'password' ++ ++ ++@pytest.mark.tier1 ++class test_login_password(XMLRPC_test, Unauthorized_HTTP_test): ++ app_uri = '/ipa/session/login_password' ++ ++ @pytest.fixture(autouse=True) ++ def login_setup(self, request): ++ ccache = os.path.join('/tmp', str(uuid.uuid4())) ++ try: ++ api.Command['user_add'](uid=testuser, givenname=u'Test', sn=u'User') ++ api.Command['passwd'](testuser, password=password) ++ run(['kinit', testuser], stdin='{0}\n{0}\n{0}\n'.format(password), ++ env={"KRB5CCNAME": ccache}) ++ except errors.ExecutionError as e: ++ pytest.skip( ++ 'Cannot set up test user: %s' % e ++ ) ++ ++ def fin(): ++ try: ++ api.Command['user_del']([testuser]) ++ except errors.NotFound: ++ pass ++ os.unlink(ccache) ++ ++ request.addfinalizer(fin) ++ ++ def _login(self, user, password, host=None): ++ return self.send_request(params={'user': str(user), ++ 'password' : str(password)}, ++ host=host) ++ ++ def test_bad_options(self): ++ for params in ( ++ None, # no params ++ {"user": "foo"}, # missing options ++ {"user": "foo", "password": ""}, # empty option ++ ): ++ response = self.send_request(params=params) ++ assert_equal(response.status, 400) ++ assert_equal(response.reason, 'Bad Request') ++ ++ def test_invalid_auth(self): ++ response = self._login(testuser, 'wrongpassword') ++ ++ assert_equal(response.status, 401) ++ assert_equal(response.getheader('X-IPA-Rejection-Reason'), ++ 'invalid-password') ++ ++ def test_invalid_referer(self): ++ response = self._login(testuser, password, 'attacker.test') ++ ++ assert_equal(response.status, 400) ++ ++ def test_success(self): ++ response = self._login(testuser, password) ++ ++ assert_equal(response.status, 200) ++ assert response.getheader('X-IPA-Rejection-Reason') is None +diff --git a/ipatests/test_ipaserver/test_referer.py b/ipatests/test_ipaserver/test_referer.py +new file mode 100644 +index 000000000..4eade8bba +--- /dev/null ++++ b/ipatests/test_ipaserver/test_referer.py +@@ -0,0 +1,136 @@ ++# Copyright (C) 2023 Red Hat ++# see file 'COPYING' for use and warranty information ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++import os ++import pytest ++import uuid ++ ++from ipatests.test_ipaserver.httptest import Unauthorized_HTTP_test ++from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test ++from ipatests.util import assert_equal ++from ipalib import api, errors ++from ipapython.ipautil import run ++ ++testuser = u'tuser' ++password = u'password' ++ ++ ++@pytest.mark.tier1 ++class test_referer(XMLRPC_test, Unauthorized_HTTP_test): ++ ++ @pytest.fixture(autouse=True) ++ def login_setup(self, request): ++ ccache = os.path.join('/tmp', str(uuid.uuid4())) ++ tokenid = None ++ try: ++ api.Command['user_add'](uid=testuser, givenname=u'Test', sn=u'User') ++ api.Command['passwd'](testuser, password=password) ++ run(['kinit', testuser], stdin='{0}\n{0}\n{0}\n'.format(password), ++ env={"KRB5CCNAME": ccache}) ++ result = api.Command["otptoken_add"]( ++ type='HOTP', description='testotp', ++ ipatokenotpalgorithm='sha512', ipatokenowner=testuser, ++ ipatokenotpdigits='6') ++ tokenid = result['result']['ipatokenuniqueid'][0] ++ except errors.ExecutionError as e: ++ pytest.skip( ++ 'Cannot set up test user: %s' % e ++ ) ++ ++ def fin(): ++ try: ++ api.Command['user_del']([testuser]) ++ api.Command['otptoken_del']([tokenid]) ++ except errors.NotFound: ++ pass ++ os.unlink(ccache) ++ ++ request.addfinalizer(fin) ++ ++ def _request(self, params={}, host=None): ++ # implicit is that self.app_uri is set to the appropriate value ++ return self.send_request(params=params, host=host) ++ ++ def test_login_password_valid(self): ++ """Valid authentication of a user""" ++ self.app_uri = "/ipa/session/login_password" ++ response = self._request( ++ params={'user': 'tuser', 'password': password}) ++ assert_equal(response.status, 200, self.app_uri) ++ ++ def test_change_password_valid(self): ++ """This actually changes the user password""" ++ self.app_uri = "/ipa/session/change_password" ++ response = self._request( ++ params={'user': 'tuser', ++ 'old_password': password, ++ 'new_password': 'new_password'} ++ ) ++ assert_equal(response.status, 200, self.app_uri) ++ ++ def test_sync_token_valid(self): ++ """We aren't testing that sync works, just that we can get there""" ++ self.app_uri = "/ipa/session/sync_token" ++ response = self._request( ++ params={'user': 'tuser', ++ 'first_code': '1234', ++ 'second_code': '5678', ++ 'password': 'password'}) ++ assert_equal(response.status, 200, self.app_uri) ++ ++ def test_i18n_messages_valid(self): ++ # i18n_messages requires a valid JSON request and we send ++ # nothing. If we get a 500 error then it got past the ++ # referer check. ++ self.app_uri = "/ipa/i18n_messages" ++ response = self._request() ++ assert_equal(response.status, 500, self.app_uri) ++ ++ # /ipa/session/login_x509 is not tested yet as it requires ++ # significant additional setup. ++ # This can be manually verified by adding ++ # Satisfy Any and Require all granted to the configuration ++ # section and comment out all Auth directives. The request ++ # will fail and log that there is no KRB5CCNAME which comes ++ # after the referer check. ++ ++ def test_endpoints_auth_required(self): ++ """Test endpoints that require pre-authorization which will ++ fail before we even get to the Referer check ++ """ ++ self.endpoints = { ++ "/ipa/xml", ++ "/ipa/session/login_kerberos", ++ "/ipa/session/json", ++ "/ipa/session/xml" ++ } ++ for self.app_uri in self.endpoints: ++ response = self._request(host="attacker.test") ++ ++ # referer is checked after auth ++ assert_equal(response.status, 401, self.app_uri) ++ ++ def notest_endpoints_invalid(self): ++ """Pass in a bad Referer, expect a 400 Bad Request""" ++ self.endpoints = { ++ "/ipa/session/login_password", ++ "/ipa/session/change_password", ++ "/ipa/session/sync_token", ++ } ++ for self.app_uri in self.endpoints: ++ response = self._request(host="attacker.test") ++ ++ assert_equal(response.status, 400, self.app_uri) +diff --git a/ipatests/util.py b/ipatests/util.py +index 5c0152b90..c69d98790 100644 +--- a/ipatests/util.py ++++ b/ipatests/util.py +@@ -163,12 +163,12 @@ class ExceptionNotRaised(Exception): + return self.msg % self.expected.__name__ + + +-def assert_equal(val1, val2): ++def assert_equal(val1, val2, msg=''): + """ + Assert ``val1`` and ``val2`` are the same type and of equal value. + """ + assert type(val1) is type(val2), '%r != %r' % (val1, val2) +- assert val1 == val2, '%r != %r' % (val1, val2) ++ assert val1 == val2, '%r != %r %r' % (val1, val2, msg) + + + def assert_not_equal(val1, val2): +-- +2.41.0 + diff --git a/SOURCES/0003-Upgrade-add-PKI-drop-in-file-if-missing_rhbz#2215336.patch b/SOURCES/0003-Upgrade-add-PKI-drop-in-file-if-missing_rhbz#2215336.patch deleted file mode 100644 index b719fa3..0000000 --- a/SOURCES/0003-Upgrade-add-PKI-drop-in-file-if-missing_rhbz#2215336.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 86c1426b2d376a390e87b074d3e10d85fa124abf Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Jun 21 2023 17:02:48 +0000 -Subject: Upgrade: add PKI drop-in file if missing - - -During the installation of IPA server, the installer adds a drop-in -file in /etc/systemd/system/pki-tomcatd@pki-tomcat.service.d/ipa.conf -that ensures the CA is reachable before the start command returns. -If the file is missing (for instance because the server was installed -with an old version before this drop-in was created), the upgrade -should add the file. - -Fixes: https://pagure.io/freeipa/issue/9381 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden - ---- - -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index dd22ac2..e4dc7ae 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1737,6 +1737,10 @@ def upgrade_configuration(): - os.path.join(paths.USR_SHARE_IPA_DIR, - "ipa-kdc-proxy.conf.template")) - if ca.is_configured(): -+ # Ensure that the drop-in file is present -+ if not os.path.isfile(paths.SYSTEMD_PKI_TOMCAT_IPA_CONF): -+ ca.add_ipa_wait() -+ - # Handle upgrade of AJP connector configuration - rewrite = ca.secure_ajp_connector() - if ca.ajp_secret: - -From 356ec5cbfe0876686239f938bdf54892dc30571e Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Jun 21 2023 17:02:48 +0000 -Subject: Integration test: add a test for upgrade and PKI drop-in file - - -Add an upgrade test with the following scenario: -- remove PKI drop-in file (to simulate an upgrade from an old -version) -- remove caECServerCertWithSCT profile from LDAP -- launch the ipa-server-upgrade command -- check that the upgrade added the file - -Related: https://pagure.io/freeipa/issue/9381 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden - ---- - -diff --git a/ipatests/test_integration/test_upgrade.py b/ipatests/test_integration/test_upgrade.py -index 9203503..182e3b5 100644 ---- a/ipatests/test_integration/test_upgrade.py -+++ b/ipatests/test_integration/test_upgrade.py -@@ -455,3 +455,25 @@ class TestUpgrade(IntegrationTest): - assert 'tXTRecord' in location_krb_rec - assert len(location_krb_rec['tXTRecord']) == 1 - assert location_krb_rec['tXTRecord'][0] == f'"{realm}"' -+ -+ def test_pki_dropin_file(self): -+ """Test that upgrade adds the drop-in file if missing -+ -+ Test for ticket 9381 -+ Simulate an update from a version that didn't provide -+ /etc/systemd/system/pki-tomcatd@pki-tomcat.service.d/ipa.conf, -+ remove one of the certificate profiles from LDAP and check that upgrade -+ completes successfully and adds the missing file. -+ When the drop-in file is missing, the upgrade tries to login to -+ PKI in order to migrate the profile and fails because PKI failed to -+ start. -+ """ -+ self.master.run_command(["rm", "-f", paths.SYSTEMD_PKI_TOMCAT_IPA_CONF]) -+ ldif = textwrap.dedent(""" -+ dn: cn=caECServerCertWithSCT,ou=certificateProfiles,ou=ca,o=ipaca -+ changetype: delete -+ """) -+ tasks.ldapmodify_dm(self.master, ldif) -+ self.master.run_command(['ipa-server-upgrade']) -+ assert self.master.transport.file_exists( -+ paths.SYSTEMD_PKI_TOMCAT_IPA_CONF) - diff --git a/SOURCES/0004-Upgrade-fix-replica-agreement_rhbz#2216551.patch b/SOURCES/0004-Upgrade-fix-replica-agreement_rhbz#2216551.patch deleted file mode 100644 index 4d795e4..0000000 --- a/SOURCES/0004-Upgrade-fix-replica-agreement_rhbz#2216551.patch +++ /dev/null @@ -1,233 +0,0 @@ -From d29b47512a39ada02fb371521994576cd9815a6c Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 19 Jun 2023 10:36:29 +0200 -Subject: [PATCH] Upgrade: fix replica agreement - -The upgrade checks the replication agreements to ensure that -some attributes are excluded from replication. The agreements -are stored in entries like -cn=serverToreplica,cn=replica,cn=_suffix_,cn=mapping tree,cn=config -but those entries are managed by the replication topology plugin -and should not be updated directly. The consequence is that the update -of the attributes fails and ipa-server-update prints an error message: - -Error caught updating nsDS5ReplicatedAttributeList: Server is unwilling -to perform: Entry and attributes are managed by topology plugin.No direct -modifications allowed. -Error caught updating nsDS5ReplicatedAttributeListTotal: Server is -unwilling to perform: Entry and attributes are managed by topology -plugin.No direct modifications allowed. - -The upgrade continues but the replication is not excluding -passwordgraceusertime. - -Instead of editing the agreements, perform the modifications on -the topology segments. - -Fixes: https://pagure.io/freeipa/issue/9385 -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden ---- - .../install/plugins/fix_replica_agreements.py | 80 +++++++++---------- - 1 file changed, 38 insertions(+), 42 deletions(-) - -diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py -index c0cdd3eb1..d963753d0 100644 ---- a/ipaserver/install/plugins/fix_replica_agreements.py -+++ b/ipaserver/install/plugins/fix_replica_agreements.py -@@ -22,6 +22,7 @@ import logging - from ipaserver.install import replication - from ipalib import Registry - from ipalib import Updater -+from ipalib import errors - - logger = logging.getLogger(__name__) - -@@ -41,35 +42,42 @@ class update_replica_attribute_lists(Updater): - def execute(self, **options): - # We need an LDAPClient connection to the backend - logger.debug("Start replication agreement exclude list update task") -- conn = self.api.Backend.ldap2 - -- repl = replication.ReplicationManager(self.api.env.realm, -- self.api.env.host, -- None, conn=conn) -- -- # We need to update only IPA replica agreements, not winsync -- ipa_replicas = repl.find_ipa_replication_agreements() -- -- logger.debug("Found %d agreement(s)", len(ipa_replicas)) -- -- for replica in ipa_replicas: -- for desc in replica.get('description', []): -- logger.debug('%s', desc) -- -- self._update_attr(repl, replica, -- 'nsDS5ReplicatedAttributeList', -- replication.EXCLUDES, template=EXCLUDE_TEMPLATE) -- self._update_attr(repl, replica, -- 'nsDS5ReplicatedAttributeListTotal', -- replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE) -- self._update_attr(repl, replica, -- 'nsds5ReplicaStripAttrs', replication.STRIP_ATTRS) -+ # Find suffixes -+ suffixes = self.api.Command.topologysuffix_find()['result'] -+ for suffix in suffixes: -+ suffix_name = suffix['cn'][0] -+ # Find segments -+ sgmts = self.api.Command.topologysegment_find( -+ suffix_name, all=True)['result'] -+ for segment in sgmts: -+ updates = {} -+ updates = self._update_attr( -+ segment, updates, -+ 'nsds5replicatedattributelist', -+ replication.EXCLUDES, template=EXCLUDE_TEMPLATE) -+ updates = self._update_attr( -+ segment, updates, -+ 'nsds5replicatedattributelisttotal', -+ replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE) -+ updates = self._update_attr( -+ segment, updates, -+ 'nsds5replicastripattrs', replication.STRIP_ATTRS) -+ if updates: -+ try: -+ self.api.Command.topologysegment_mod( -+ suffix_name, segment['cn'][0], -+ **updates) -+ except errors.EmptyModlist: -+ # No update done -+ logger.debug("No update required for the segment %s", -+ segment['cn'][0]) - - logger.debug("Done updating agreements") - - return False, [] # No restart, no updates - -- def _update_attr(self, repl, replica, attribute, values, template='%s'): -+ def _update_attr(self, segment, updates, attribute, values, template='%s'): - """Add or update an attribute of a replication agreement - - If the attribute doesn't already exist, it is added and set to -@@ -77,27 +85,21 @@ class update_replica_attribute_lists(Updater): - If the attribute does exist, `values` missing from it are just - appended to the end, also space-separated. - -- :param repl: Replication manager -- :param replica: Replica agreement -+ :param: updates: dict containing the updates -+ :param segment: dict containing segment information - :param attribute: Attribute to add or update - :param values: List of values the attribute should hold - :param template: Template to use when adding attribute - """ -- attrlist = replica.single_value.get(attribute) -+ attrlist = segment.get(attribute) - if attrlist is None: - logger.debug("Adding %s", attribute) - - # Need to add it altogether -- replica[attribute] = [template % " ".join(values)] -- -- try: -- repl.conn.update_entry(replica) -- logger.debug("Updated") -- except Exception as e: -- logger.error("Error caught updating replica: %s", str(e)) -+ updates[attribute] = template % " ".join(values) - - else: -- attrlist_normalized = attrlist.lower().split() -+ attrlist_normalized = attrlist[0].lower().split() - missing = [a for a in values - if a.lower() not in attrlist_normalized] - -@@ -105,14 +107,8 @@ class update_replica_attribute_lists(Updater): - logger.debug("%s needs updating (missing: %s)", attribute, - ', '.join(missing)) - -- replica[attribute] = [ -- '%s %s' % (attrlist, ' '.join(missing))] -+ updates[attribute] = '%s %s' % (attrlist[0], ' '.join(missing)) - -- try: -- repl.conn.update_entry(replica) -- logger.debug("Updated %s", attribute) -- except Exception as e: -- logger.error("Error caught updating %s: %s", -- attribute, str(e)) - else: - logger.debug("%s: No update necessary", attribute) -+ return updates --- -2.41.0 - -From 93d97b59600c15e5028ee39b0e98450544165158 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 19 Jun 2023 10:36:59 +0200 -Subject: [PATCH] Integration tests: add a test to ipa-server-upgrade - -Add an integration test ensuring that the upgrade -properly updates the attributes to be excluded from -replication. - -Related: https://pagure.io/freeipa/issue/9385 -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden ---- - .../test_simple_replication.py | 30 +++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/ipatests/test_integration/test_simple_replication.py b/ipatests/test_integration/test_simple_replication.py -index 17092a499..d1e65ef7c 100644 ---- a/ipatests/test_integration/test_simple_replication.py -+++ b/ipatests/test_integration/test_simple_replication.py -@@ -23,8 +23,10 @@ import pytest - - from ipaplatform.paths import paths - from ipapython.dn import DN -+from ipaserver.install.replication import EXCLUDES - from ipatests.pytest_ipa.integration import tasks - from ipatests.test_integration.base import IntegrationTest -+from ipatests.test_integration.test_topology import find_segment - - - def check_replication(source_host, dest_host, login): -@@ -104,6 +106,34 @@ class TestSimpleReplication(IntegrationTest): - [paths.IPA_CUSTODIA_CHECK, self.master.hostname] - ) - -+ def test_fix_agreements(self): -+ """Test that upgrade fixes the list of attributes excluded from repl -+ -+ Test for ticket 9385 -+ """ -+ # Prepare the server by removing some values from -+ # from the nsDS5ReplicatedAttributeList -+ segment = find_segment(self.master, self.replicas[0], "domain") -+ self.master.run_command([ -+ "ipa", "topologysegment-mod", "domain", segment, -+ "--replattrs", -+ "(objectclass=*) $ EXCLUDE memberof idnssoaserial entryusn"]) -+ # Run the upgrade -+ result = self.master.run_command(["ipa-server-upgrade"]) -+ # Ensure that the upgrade updated the attribute without error -+ errmsg = "Error caught updating nsDS5ReplicatedAttributeList" -+ assert errmsg not in result.stdout_text -+ # Check the updated value -+ suffix = DN(self.master.domain.basedn) -+ dn = DN(('cn', str(suffix)), ('cn', 'mapping tree'), ('cn', 'config')) -+ result = tasks.ldapsearch_dm(self.master, str(dn), -+ ["nsDS5ReplicatedAttributeList"]) -+ output = result.stdout_text.lower() -+ -+ template = 'nsDS5ReplicatedAttributeList: (objectclass=*) $ EXCLUDE %s' -+ expected_value = template % " ".join(EXCLUDES) -+ assert expected_value.lower() in output -+ - def test_replica_removal(self): - """Test replica removal""" - result = self.master.run_command(['ipa-replica-manage', 'list']) --- -2.41.0 - diff --git a/SOURCES/0004-ipa-kdb-Detect-and-block-Bronze-Bit-attacks.patch b/SOURCES/0004-ipa-kdb-Detect-and-block-Bronze-Bit-attacks.patch new file mode 100644 index 0000000..e7abc58 --- /dev/null +++ b/SOURCES/0004-ipa-kdb-Detect-and-block-Bronze-Bit-attacks.patch @@ -0,0 +1,265 @@ +From 013be398bced31f567ef01ac2471cb7529789b4a Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Mon, 9 Oct 2023 15:47:03 +0200 +Subject: [PATCH] ipa-kdb: Detect and block Bronze-Bit attacks + +The C8S/RHEL8 version of FreeIPA is vulnerable to the Bronze-Bit attack +because it does not implement PAC ticket signature to protect the +"forwardable" flag. However, it does implement the PAC extended KDC +signature, which protects against PAC spoofing. + +Based on information available in the PAC and the +"ok-to-auth-as-delegate" attribute in the database. It is possible to +detect and reject requests where the "forwardable" flag was flipped by +the attacker in the evidence ticket. +--- + daemons/ipa-kdb/ipa_kdb.h | 13 +++ + daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 6 + + daemons/ipa-kdb/ipa_kdb_mspac.c | 173 ++++++++++++++++++++++++++++ + ipaserver/install/server/install.py | 8 ++ + 4 files changed, 200 insertions(+) + +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 7aa5be494..02b2cb631 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -367,6 +367,19 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + const char *test_realm, size_t size, + char **trusted_realm); + ++/* Try to detect a Bronze-Bit attack based on the content of the request and ++ * data from the KDB. ++ * ++ * context krb5 context ++ * request KDB request ++ * detected Set to "true" if a bronze bit attack is detected and the ++ * pointer is not NULL. Remains unset otherwise. ++ * status If the call fails and the pointer is not NULL, set it with a ++ * message describing the cause of the failure. */ ++krb5_error_code ++ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, ++ bool *detected, const char **status); ++ + /* DELEGATION CHECKS */ + + krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext, +diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +index f2804c9b2..1032dff0b 100644 +--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +@@ -185,6 +185,12 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata, + const char **status, krb5_deltat *lifetime_out, + krb5_deltat *renew_lifetime_out) + { ++ krb5_error_code kerr; ++ ++ kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status); ++ if (kerr) ++ return KRB5KDC_ERR_POLICY; ++ + *status = NULL; + *lifetime_out = 0; + *renew_lifetime_out = 0; +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 83cb9914d..b4e22d431 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3298,3 +3298,176 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + + return KRB5_KDB_NOENTRY; + } ++ ++krb5_error_code ++ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, ++ bool *detected, const char **status) ++{ ++ krb5_error_code kerr; ++ const char *st = NULL; ++ size_t i, j; ++ krb5_ticket *evidence_tkt; ++ krb5_authdata **authdata, **ifrel = NULL; ++ krb5_pac pac = NULL; ++ TALLOC_CTX *tmpctx = NULL; ++ krb5_data fullsign = { 0, 0, NULL }, linfo_blob = { 0, 0, NULL }; ++ DATA_BLOB linfo_data; ++ struct PAC_LOGON_INFO_CTR linfo; ++ enum ndr_err_code ndr_err; ++ struct dom_sid asserted_identity_sid; ++ bool evtkt_is_s4u2self = false; ++ krb5_db_entry *proxy_entry = NULL; ++ ++ /* If no additional ticket, this is not a constrained delegateion request. ++ * Skip checks. */ ++ if (!(request->kdc_options & KDC_OPT_CNAME_IN_ADDL_TKT)) { ++ kerr = 0; ++ goto end; ++ } ++ ++ evidence_tkt = request->second_ticket[0]; ++ ++ /* No need to check the Forwardable flag. If it was not set, this request ++ * would have failed earlier. */ ++ ++ /* We only support general constrained delegation (not RBCD), which is not ++ * available for cross-realms. */ ++ if (!krb5_realm_compare(context, evidence_tkt->server, request->server)) { ++ st = "S4U2PROXY_NOT_SUPPORTED_FOR_CROSS_REALMS"; ++ kerr = ENOTSUP; ++ goto end; ++ } ++ ++ authdata = evidence_tkt->enc_part2->authorization_data; ++ ++ /* Search for the PAC. */ ++ for (i = 0; authdata != NULL && authdata[i] != NULL; i++) { ++ if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT) ++ continue; ++ ++ kerr = krb5_decode_authdata_container(context, ++ KRB5_AUTHDATA_IF_RELEVANT, ++ authdata[i], &ifrel); ++ if (kerr) { ++ st = "S4U2PROXY_CANNOT_DECODE_EVIDENCE_TKT_AUTHDATA"; ++ goto end; ++ } ++ ++ for (j = 0; ifrel[j] != NULL; j++) { ++ if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC) ++ break; ++ } ++ if (ifrel[j] != NULL) ++ break; ++ ++ krb5_free_authdata(context, ifrel); ++ ifrel = NULL; ++ } ++ ++ if (ifrel == NULL) { ++ st = "S4U2PROXY_EVIDENCE_TKT_WITHOUT_PAC"; ++ kerr = ENOENT; ++ goto end; ++ } ++ ++ /* Parse the PAC. */ ++ kerr = krb5_pac_parse(context, ifrel[j]->contents, ifrel[j]->length, &pac); ++ if (kerr) { ++ st = "S4U2PROXY_CANNOT_DECODE_EVICENCE_TKT_PAC"; ++ goto end; ++ } ++ ++ /* Check that the PAC extanded KDC signature is present. If it is, it was ++ * already tested. ++ * If absent, the context of the PAC cannot be trusted. */ ++ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_FULL_CHECKSUM, &fullsign); ++ if (kerr) { ++ st = "S4U2PROXY_MISSING_EXTENDED_KDC_SIGN_IN_EVIDENCE_TKT_PAC"; ++ goto end; ++ } ++ ++ /* Get the PAC Logon Info. */ ++ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_LOGON_INFO, &linfo_blob); ++ if (kerr) { ++ st = "S4U2PROXY_NO_PAC_LOGON_INFO_IN_EVIDENCE_TKT"; ++ goto end; ++ } ++ ++ /* Parse the PAC Logon Info. */ ++ tmpctx = talloc_new(NULL); ++ if (!tmpctx) { ++ st = "OUT_OF_MEMORY"; ++ kerr = ENOMEM; ++ goto end; ++ } ++ ++ linfo_data.length = linfo_blob.length; ++ linfo_data.data = (uint8_t *)linfo_blob.data; ++ ndr_err = ndr_pull_union_blob(&linfo_data, tmpctx, &linfo, ++ PAC_TYPE_LOGON_INFO, ++ (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO); ++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ++ st = "S4U2PROXY_CANNOT_PARSE_ENVIDENCE_TKT_PAC_LOGON_INFO"; ++ kerr = EINVAL; ++ goto end; ++ } ++ ++ /* Check that the extra SIDs array is not empty. */ ++ if (linfo.info->info3.sidcount == 0) { ++ st = "S4U2PROXY_NO_EXTRA_SID"; ++ kerr = ENOENT; ++ goto end; ++ } ++ ++ /* Search for the S-1-18-2 domain SID, which indicates the ticket was ++ * obtained using S4U2Self */ ++ kerr = ipadb_string_to_sid("S-1-18-2", &asserted_identity_sid); ++ if (kerr) { ++ st = "S4U2PROXY_CANNOT_CREATE_ASSERTED_IDENTITY_SID"; ++ goto end; ++ } ++ ++ for (i = 0; i < linfo.info->info3.sidcount; i++) { ++ if (dom_sid_check(&asserted_identity_sid, ++ linfo.info->info3.sids[0].sid, true)) { ++ evtkt_is_s4u2self = true; ++ break; ++ } ++ } ++ ++ /* If the ticket was obtained using S4U2Self, the proxy principal entry must ++ * have the "ok_to_auth_as_delegate" attribute set to true. */ ++ if (evtkt_is_s4u2self) { ++ kerr = ipadb_get_principal(context, evidence_tkt->server, 0, ++ &proxy_entry); ++ if (kerr) { ++ st = "S4U2PROXY_CANNOT_FIND_PROXY_PRINCIPAL"; ++ goto end; ++ } ++ ++ if (!(proxy_entry->attributes & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE)) { ++ /* This evidence ticket cannot be forwardable given the privileges ++ * of the proxy principal. ++ * This is a Bronze Bit attack. */ ++ if (detected) ++ *detected = true; ++ st = "S4U2PROXY_BRONZE_BIT_ATTACK_DETECTED"; ++ kerr = EBADE; ++ goto end; ++ } ++ } ++ ++ kerr = 0; ++ ++end: ++ if (st && status) ++ *status = st; ++ ++ krb5_free_authdata(context, ifrel); ++ krb5_pac_free(context, pac); ++ krb5_free_data_contents(context, &linfo_blob); ++ krb5_free_data_contents(context, &fullsign); ++ talloc_free(tmpctx); ++ ipadb_free_principal(context, proxy_entry); ++ return kerr; ++} +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 4e4076410..bfbb83bcb 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -981,6 +981,14 @@ def install(installer): + # Set the admin user kerberos password + ds.change_admin_password(admin_password) + ++ # Force KDC to refresh the cached value of ipaKrbAuthzData by restarting. ++ # ipaKrbAuthzData has to be set with "MS-PAC" to trigger PAC generation, ++ # which is required to handle S4U2Proxy with the Bronze-Bit fix. ++ # Not doing so would cause API malfunction for around a minute, which is ++ # long enough to cause the hereafter client installation to fail. ++ service.print_msg("Restarting the KDC") ++ krb.restart() ++ + # Call client install script + service.print_msg("Configuring client side components") + try: +-- +2.41.0 + diff --git a/SOURCES/0005-Improve-server-affinity-for-ca-less-deployments_rhel#22283.patch b/SOURCES/0005-Improve-server-affinity-for-ca-less-deployments_rhel#22283.patch new file mode 100644 index 0000000..000591c --- /dev/null +++ b/SOURCES/0005-Improve-server-affinity-for-ca-less-deployments_rhel#22283.patch @@ -0,0 +1,212 @@ +From 3add9ba03a0af913d03b1f5ecaa8e48e46a93f91 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Jan 15 2024 13:42:08 +0000 +Subject: Server affinity: Retain user-requested remote server + + +We want to avoid splitting a replica server installation between +two hosts where possible so if a CA or KRA is requested then +we only try to install against a remote server that also provides +those capabilities. This avoids race conditions. + +If a CA or KRA is not requested and the user has provided a +server to install against then use that instead of overriding it. + +Extend the logic of picking the remote Custodia mode +(KRA, CA, *MASTER*) to include considering whether the +CA and KRA services are requested. If the service(s) are +not requested the the associated hostname may not be +reliable. + +Fixes: https://pagure.io/freeipa/issue/9491 +Related: https://pagure.io/freeipa/issue/9289 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud + +--- + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 27fbdef..8096b6a 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -782,6 +782,7 @@ def promotion_check_host_principal_auth_ind(conn, hostdn): + + + def remote_connection(config): ++ logger.debug("Creating LDAP connection to %s", config.master_host_name) + ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name) + xmlrpc_uri = 'https://{}/ipa/xml'.format( + ipautil.format_netloc(config.master_host_name)) +@@ -1087,7 +1088,7 @@ def promote_check(installer): + 'CA', conn, preferred_cas + ) + if ca_host is not None: +- if config.master_host_name != ca_host: ++ if options.setup_ca and config.master_host_name != ca_host: + conn.disconnect() + del remote_api + config.master_host_name = ca_host +@@ -1096,8 +1097,7 @@ def promote_check(installer): + conn = remote_api.Backend.ldap2 + conn.connect(ccache=installer._ccache) + config.ca_host_name = ca_host +- config.master_host_name = ca_host +- ca_enabled = True ++ ca_enabled = True # There is a CA somewhere in the topology + if options.dirsrv_cert_files: + logger.error("Certificates could not be provided when " + "CA is present on some master.") +@@ -1135,7 +1135,7 @@ def promote_check(installer): + 'KRA', conn, preferred_kras + ) + if kra_host is not None: +- if config.master_host_name != kra_host: ++ if options.setup_kra and config.master_host_name != kra_host: + conn.disconnect() + del remote_api + config.master_host_name = kra_host +@@ -1143,10 +1143,9 @@ def promote_check(installer): + installer._remote_api = remote_api + conn = remote_api.Backend.ldap2 + conn.connect(ccache=installer._ccache) +- config.kra_host_name = kra_host +- config.ca_host_name = kra_host +- config.master_host_name = kra_host +- kra_enabled = True ++ config.kra_host_name = kra_host ++ config.ca_host_name = kra_host ++ kra_enabled = True # There is a KRA somewhere in the topology + if options.setup_kra and options.server and \ + kra_host != options.server: + # Installer was provided with a specific master +@@ -1372,10 +1371,10 @@ def install(installer): + otpd.create_instance('OTPD', config.host_name, + ipautil.realm_to_suffix(config.realm_name)) + +- if kra_enabled: ++ if options.setup_kra and kra_enabled: + # A KRA peer always provides a CA, too. + mode = custodiainstance.CustodiaModes.KRA_PEER +- elif ca_enabled: ++ elif options.setup_ca and ca_enabled: + mode = custodiainstance.CustodiaModes.CA_PEER + else: + mode = custodiainstance.CustodiaModes.MASTER_PEER + +From 701339d4fed539713eb1a13495992879f56a6daa Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Jan 18 2024 14:53:28 +0000 +Subject: Server affinity: Don't rely just on [ca|kra]_enabled for installs + + +ca_enable and kra_enabled are intended to be used to identify that +a CA or KRA is available in the topology. It was also being used +to determine whether a CA or KRA service is desired on a replica +install, rather than options.setup_[ca|kra] + +Fixes: https://pagure.io/freeipa/issue/9510 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud + +--- + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 8096b6a..191913d 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1143,7 +1143,8 @@ def promote_check(installer): + installer._remote_api = remote_api + conn = remote_api.Backend.ldap2 + conn.connect(ccache=installer._ccache) +- config.kra_host_name = kra_host ++ config.kra_host_name = kra_host ++ if options.setup_kra: # only reset ca_host if KRA is requested + config.ca_host_name = kra_host + kra_enabled = True # There is a KRA somewhere in the topology + if options.setup_kra and options.server and \ +@@ -1381,7 +1382,7 @@ def install(installer): + custodia = custodiainstance.get_custodia_instance(config, mode) + custodia.create_instance() + +- if ca_enabled: ++ if options.setup_ca and ca_enabled: + options.realm_name = config.realm_name + options.domain_name = config.domain_name + options.host_name = config.host_name +@@ -1397,7 +1398,7 @@ def install(installer): + service.print_msg("Finalize replication settings") + ds.finalize_replica_config() + +- if kra_enabled: ++ if options.setup_kra and kra_enabled: + kra.install(api, config, options, custodia=custodia) + + service.print_msg("Restarting the KDC") + +From e6014a5c1996528b255480b67fe2937203bff81b Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Jan 23 2024 15:32:58 +0000 +Subject: Server affinity: call ca.install() if there is a CA in the topology + + +This should not have been gated on options.setup_ca because we need +the RA agent on all servers if there is a CA in the topology otherwise +the non-CA servers won't be able to communicate with the CA. + +Fixes: https://pagure.io/freeipa/issue/9510 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud + +--- + +diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py +index c93ae1f..187f803 100644 +--- a/ipaserver/install/ca.py ++++ b/ipaserver/install/ca.py +@@ -387,9 +387,10 @@ def install_step_0(standalone, replica_config, options, custodia): + promote = False + else: + cafile = os.path.join(replica_config.dir, 'cacert.p12') +- custodia.get_ca_keys( +- cafile, +- replica_config.dirman_password) ++ if replica_config.setup_ca: ++ custodia.get_ca_keys( ++ cafile, ++ replica_config.dirman_password) + + ca_signing_algorithm = None + ca_type = None +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index f8d4733..4c1c07c 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1359,11 +1359,13 @@ def install(installer): + custodia = custodiainstance.get_custodia_instance(config, mode) + custodia.create_instance() + +- if options.setup_ca and ca_enabled: ++ if ca_enabled: + options.realm_name = config.realm_name + options.domain_name = config.domain_name + options.host_name = config.host_name + options.dm_password = config.dirman_password ++ # Always call ca.install() if there is a CA in the topology ++ # to ensure the RA agent is present. + ca.install(False, config, options, custodia=custodia) + + # configure PKINIT now that all required services are in place +@@ -1375,7 +1377,8 @@ def install(installer): + service.print_msg("Finalize replication settings") + ds.finalize_replica_config() + +- if options.setup_kra and kra_enabled: ++ if kra_enabled: ++ # The KRA installer checks for itself the status of setup_kra + kra.install(api, config, options, custodia=custodia) + + service.print_msg("Restarting the KDC") + diff --git a/SOURCES/0005-OTP-fix-data-type-to-avoid-endianness-issue_rhbz#2218293.patch b/SOURCES/0005-OTP-fix-data-type-to-avoid-endianness-issue_rhbz#2218293.patch deleted file mode 100644 index 6d5b7b6..0000000 --- a/SOURCES/0005-OTP-fix-data-type-to-avoid-endianness-issue_rhbz#2218293.patch +++ /dev/null @@ -1,52 +0,0 @@ -From a7e167154b889f75463ccc9cd91a75c1afb22da9 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Jun 28 2023 19:43:16 +0000 -Subject: OTP: fix data type to avoid endianness issue - - -When 389-ds process an OTP authentication, the ipa-pwd-extop -plugin reads a buffer to extract the authentication type. -The type is stored in an int but the data is a ber_tag_t. - -On big endian machines the type cast does not cause any issue -but on s390x the buffer that should return 128 is seen as 0. - -As a consequence, the plugin considers that the method is not -LDAP_AUTH_SIMPLE and exits early, without processing the OTP. - -The fix is simple and consists in using the right type -(ber_tag_t is an unsigned long). - -Fixes: https://pagure.io/freeipa/issue/9402 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden - ---- - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -index 9375941..4562652 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -@@ -1433,7 +1433,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) - Slapi_DN *target_sdn = NULL; - Slapi_DN *sdn = NULL; - const char *dn = NULL; -- int method = 0; -+ ber_tag_t method = 0; - bool syncreq; - bool otpreq; - int ret = 0; -@@ -1454,8 +1454,10 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) - } - - /* We're only interested in simple authentication. */ -- if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0) -+ if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0) { -+ LOG("Not handled (not simple bind or NULL dn/credentials)\n"); - return 0; -+ } - - /* Retrieve the user's entry. */ - sdn = slapi_sdn_dup(target_sdn); - diff --git a/SOURCES/0006-Backport-test-updates-8-9-release_rhbz#2218847.patch b/SOURCES/0006-Backport-test-updates-8-9-release_rhbz#2218847.patch deleted file mode 100644 index 8b44931..0000000 --- a/SOURCES/0006-Backport-test-updates-8-9-release_rhbz#2218847.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 7a94acca6a9efb546f1cf59f63fcb89f98944ea5 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Thu, 25 May 2023 08:16:33 +0200 -Subject: [PATCH] ACME tests: fix issue_and_expire_acme_cert method - -The fixture issue_and_expire_acme_cert is changing the date -on master and client. It also resets the admin password as -it gets expired after the date change. -Currently the code is resetting the password by performing -kinit on the client, which leaves the master with an expired -ticket in its cache. Reset the password on the master instead -in order to have a valid ticket for the next operations. - -Fixes: https://pagure.io/freeipa/issue/9383 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Mohammad Rizwan ---- - ipatests/test_integration/test_acme.py | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py -index c73f441fc..c69e810da 100644 ---- a/ipatests/test_integration/test_acme.py -+++ b/ipatests/test_integration/test_acme.py -@@ -583,20 +583,20 @@ class TestACMERenew(IntegrationTest): - tasks.kdestroy_all(host) - tasks.move_date(host, 'stop', '+90days') - -- tasks.get_kdcinfo(host) -+ tasks.get_kdcinfo(self.master) - # Note raiseonerr=False: - # the assert is located after kdcinfo retrieval. - # run kinit command repeatedly until sssd gets settle - # after date change - tasks.run_repeatedly( -- host, "KRB5_TRACE=/dev/stdout kinit admin", -+ self.master, "KRB5_TRACE=/dev/stdout kinit admin", - stdin_text='{0}\n{0}\n{0}\n'.format( -- self.clients[0].config.admin_password -+ self.master.config.admin_password - ) - ) - # Retrieve kdc.$REALM after the password change, just in case SSSD - # domain status flipped to online during the password change. -- tasks.get_kdcinfo(host) -+ tasks.get_kdcinfo(self.master) - - yield - --- -2.41.0 - -From 998bafee86a870ad1ea4d6bccf12f0fae64c398c Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Wed, 31 May 2023 11:50:14 +0200 -Subject: [PATCH] ipatest: remove xfail from test_smb - -test_smb is now successful because the windows server version -has been updated to windows-server-2022 with -- KB5012170 -- KB5025230 -- KB5022507 -- servicing stack 10.0.20348.1663 -in freeipa-pr-ci commit 3ba4151. - -Remove the xfail. - -Fixes: https://pagure.io/freeipa/issue/9124 -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Mohammad Rizwan ---- - ipatests/test_integration/test_smb.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/ipatests/test_integration/test_smb.py b/ipatests/test_integration/test_smb.py -index 30f8d5901..eb3981bdd 100644 ---- a/ipatests/test_integration/test_smb.py -+++ b/ipatests/test_integration/test_smb.py -@@ -349,7 +349,6 @@ class TestSMB(IntegrationTest): - @pytest.mark.skipif( - osinfo.id == 'fedora' and osinfo.version_number <= (31,), - reason='Test requires krb 1.18') -- @pytest.mark.xfail(reason="Pagure ticket 9124", strict=True) - def test_smb_service_s4u2self(self): - """Test S4U2Self operation by IPA service - against both AD and IPA users --- -2.41.0 - -From 1b51fa4cb07380d1102891233e85a7940f804c72 Mon Sep 17 00:00:00 2001 -From: Anuja More -Date: Thu, 11 May 2023 12:50:10 +0530 -Subject: [PATCH] ipatests: Check that SSSD_PUBCONF_KRB5_INCLUDE_D_DIR is not - included in krb5.conf - -SSSD already provides a config snippet which includes -SSSD_PUBCONF_KRB5_INCLUDE_D_DIR, and having both breaks Java. -Test checks that krb5.conf does not include -SSSD_PUBCONF_KRB5_INCLUDE_D_DIR. - -Related: https://pagure.io/freeipa/issue/9267 - -Signed-off-by: Anuja More -Reviewed-By: Florence Blanc-Renaud ---- - .../test_integration/test_installation_client.py | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/ipatests/test_integration/test_installation_client.py b/ipatests/test_integration/test_installation_client.py -index 014b0f6ab..56e1593bf 100644 ---- a/ipatests/test_integration/test_installation_client.py -+++ b/ipatests/test_integration/test_installation_client.py -@@ -76,6 +76,21 @@ class TestInstallClient(IntegrationTest): - result = self.clients[0].run_command(['cat', '/etc/ssh/ssh_config']) - assert 'HostKeyAlgorithms' not in result.stdout_text - -+ def test_client_install_with_krb5(self): -+ """Test that SSSD_PUBCONF_KRB5_INCLUDE_D_DIR is not added in krb5.conf -+ -+ SSSD already provides a config snippet which includes -+ SSSD_PUBCONF_KRB5_INCLUDE_D_DIR, and having both breaks Java. -+ Test checks that krb5.conf does not include -+ SSSD_PUBCONF_KRB5_INCLUDE_D_DIR. -+ -+ related: https://pagure.io/freeipa/issue/9267 -+ """ -+ krb5_cfg = self.master.get_file_contents(paths.KRB5_CONF) -+ assert 'includedir {dir}'.format( -+ dir=paths.SSSD_PUBCONF_KRB5_INCLUDE_D_DIR -+ ).encode() not in krb5_cfg -+ - - class TestClientInstallBind(IntegrationTest): - """ --- -2.41.0 - -From f599e2d67bad5945e4dcf99fdd584f01f1e20d1e Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Tue, 6 Jun 2023 09:04:48 +0200 -Subject: [PATCH] webuitests: close notification which hides Add button - -The webui test test_service.py::test_service::test_arbitrary_certificates -randomly fails. -The test is creating a new service then navigates to the Service page -and clicks on the Add Certificate button. -The notification area may still be present and hide the button, with -the message "Service successfully added". -Close all notifications before navigating to the Service page. - -Fixes: https://pagure.io/freeipa/issue/9389 -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Michal Polovka ---- - ipatests/test_webui/test_service.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py -index f1d9a9d62..e2976d73a 100644 ---- a/ipatests/test_webui/test_service.py -+++ b/ipatests/test_webui/test_service.py -@@ -296,6 +296,7 @@ class test_service(sevice_tasks): - cert_widget_sel = "div.certificate-widget" - - self.add_record(ENTITY, data) -+ self.close_notifications() - self.navigate_to_record(pkey) - - # check whether certificate section is present --- -2.41.0 - diff --git a/SOURCES/0006-host-update-System-Manage-Host-Keytab-permission_rhel#22286.patch b/SOURCES/0006-host-update-System-Manage-Host-Keytab-permission_rhel#22286.patch new file mode 100644 index 0000000..05b6a46 --- /dev/null +++ b/SOURCES/0006-host-update-System-Manage-Host-Keytab-permission_rhel#22286.patch @@ -0,0 +1,97 @@ +From 3842116185de6ae8714f30b57bd75c7eddde53d8 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Jan 15 2024 13:50:10 +0000 +Subject: host: update System: Manage Host Keytab permission + + +Since commit 5c0e7a5fb420377dcc06a956695afdcb35196444, a new extended +operation to get a keytab is supposed to be used. This keytab +setting/retrieval extended operation checks access rights of the bound +DN to write to a virtual attribute 'ipaProtectedOperation;write_keys'. + +If the write isn't allowed, the operation is rejected and ipa-getkeytab +tool falls back to an older code that generates the keytab on the client +and forcibly sets to the LDAP entry. For the latter, a check is done to +make sure the bound DN is allowed to write to 'krbPrincipalKey' attribute. + +This fallback should never happen for newer deployments. When enrollemnt +operation is delegated to non-administrative user with the help of 'Host +Enrollment' role, a host can be pre-created or created at enrollment +time, if this non-administrative user has 'Host Administrators' role. In +the latter case a system permission 'System: Manage Host Keytab' grants +write access to 'krbPrincipalKey' attribute but lacks any access to the +virtual attributes expected by the new extended operation. + +There is a second virtual attribute, 'ipaProtectedOperation;read_keys', +that allows to retrieve existing keys for a host. However, during +initial enrollment we do not allow to retrieve and reuse existing +Kerberos key: while 'ipa-getkeytab -r' would give ability to retrieve +the existing key, 'ipa-join' has no way to trigger that operation. +Hence, permission 'System: Manage Host Keytab' will not grant the right +to read the Kerberos key via extended operation used by 'ipa-getkeytab +-r'. Such operation can be done later by utilizing 'ipa +service/host-allow-retrieve-keytab' commands. + +Fix 'System: Manage Host Keytab' permission and extend a permission test +to see that we do not fallback to the old extended operation. + +Fixes: https://pagure.io/freeipa/issue/9496 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Rob Crittenden + +--- + +diff --git a/ACI.txt b/ACI.txt +index e6d6e3d..236bb43 100644 +--- a/ACI.txt ++++ b/ACI.txt +@@ -147,7 +147,7 @@ aci: (targetattr = "usercertificate")(targetfilter = "(objectclass=ipahost)")(ve + dn: cn=computers,cn=accounts,dc=ipa,dc=example + aci: (targetattr = "userpassword")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Enrollment Password";allow (write) groupdn = "ldap:///cn=System: Manage Host Enrollment Password,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=computers,cn=accounts,dc=ipa,dc=example +-aci: (targetattr = "krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++aci: (targetattr = "ipaprotectedoperation;write_keys || krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=computers,cn=accounts,dc=ipa,dc=example + aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys || ipaallowedtoperform;write_keys || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Keytab Permissions";allow (compare,read,search,write) groupdn = "ldap:///cn=System: Manage Host Keytab Permissions,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=computers,cn=accounts,dc=ipa,dc=example +diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py +index 3ef510e..b02c8b5 100644 +--- a/ipaserver/plugins/host.py ++++ b/ipaserver/plugins/host.py +@@ -409,7 +409,8 @@ class host(LDAPObject): + api.env.container_hostgroup, + api.env.basedn), + ], +- 'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey'}, ++ 'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey', ++ 'ipaprotectedoperation;write_keys'}, + 'replaces': [ + '(targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage host keytab";allow (write) groupdn = "ldap:///cn=Manage host keytab,cn=permissions,cn=pbac,$SUFFIX";)', + ], +diff --git a/ipatests/test_integration/test_user_permissions.py b/ipatests/test_integration/test_user_permissions.py +index 3333a4f..cd1096f 100644 +--- a/ipatests/test_integration/test_user_permissions.py ++++ b/ipatests/test_integration/test_user_permissions.py +@@ -277,6 +277,9 @@ class TestInstallClientNoAdmin(IntegrationTest): + self.master.run_command(['ipa', 'privilege-add-permission', + '--permissions', 'System: Add Hosts', + 'Add Hosts']) ++ self.master.run_command(['ipa', 'privilege-add-permission', ++ '--permissions', 'System: Manage Host Keytab', ++ 'Add Hosts']) + + self.master.run_command(['ipa', 'role-add-privilege', 'useradmin', + '--privileges', 'Host Enrollment']) +@@ -301,6 +304,10 @@ class TestInstallClientNoAdmin(IntegrationTest): + encoding='utf-8') + assert msg in install_log + ++ # Make sure we do not fallback to an old keytab retrieval method anymore ++ msg = "Retrying with pre-4.0 keytab retrieval method..." ++ assert msg not in install_log ++ + # check that user is able to request a host cert, too + result = tasks.run_certutil(client, ['-L'], paths.IPA_NSSDB_DIR) + assert 'Local IPA host' in result.stdout_text + diff --git a/SOURCES/0007-adtrustinstance-make-sure-NetBIOS-name-defaults-are-set-properly_rhel#21938.patch b/SOURCES/0007-adtrustinstance-make-sure-NetBIOS-name-defaults-are-set-properly_rhel#21938.patch new file mode 100644 index 0000000..09b62e0 --- /dev/null +++ b/SOURCES/0007-adtrustinstance-make-sure-NetBIOS-name-defaults-are-set-properly_rhel#21938.patch @@ -0,0 +1,32 @@ +From 2f17319df6147832dceff7c06154363f8d58b194 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Jan 18 2024 09:07:31 +0000 +Subject: adtrustinstance: make sure NetBIOS name defaults are set properly + + +Some tools may pass None as NetBIOS name if not put explicitly by a +user. This meant to use default NetBIOS name generator based on the +domain (realm) name. However, this wasn't done properly, so None is +passed later to python-ldap and it rejects such LDAP entry. + +Fixes: https://pagure.io/freeipa/issue/9514 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud + +--- + +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index bf0cc3b..bb5b61a 100644 +--- a/ipaserver/install/adtrustinstance.py ++++ b/ipaserver/install/adtrustinstance.py +@@ -189,6 +189,8 @@ class ADTRUSTInstance(service.Service): + self.fqdn = self.fqdn or api.env.host + self.host_netbios_name = make_netbios_name(self.fqdn) + self.realm = self.realm or api.env.realm ++ if not self.netbios_name: ++ self.netbios_name = make_netbios_name(self.realm) + + self.suffix = ipautil.realm_to_suffix(self.realm) + self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \ + diff --git a/SOURCES/0007-ipa-kdb-fix-error-handling-of-is_master_host_rhbz#2214638.patch b/SOURCES/0007-ipa-kdb-fix-error-handling-of-is_master_host_rhbz#2214638.patch deleted file mode 100644 index 39d9e7f..0000000 --- a/SOURCES/0007-ipa-kdb-fix-error-handling-of-is_master_host_rhbz#2214638.patch +++ /dev/null @@ -1,85 +0,0 @@ -From b5793c854035a122ed4c66f917cc427e5024e46a Mon Sep 17 00:00:00 2001 -From: Julien Rische -Date: Aug 02 2023 11:52:30 +0000 -Subject: ipa-kdb: fix error handling of is_master_host() - - -Adding proper error handling to the is_master_host() function to allow -it to make the difference between the absence of a master host object -and a connection failure. This will keep the krb5kdc daemon from -continuing to run with a NULL LDAP context. - -Fixes: https://pagure.io/freeipa/issue/9422 - -Signed-off-by: Julien Rische -Reviewed-By: Alexander Bokovoy - ---- - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 8da7543..83cb991 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -401,27 +401,29 @@ static krb5_error_code ipadb_add_asserted_identity(struct ipadb_context *ipactx, - return 0; - } - --static bool is_master_host(struct ipadb_context *ipactx, const char *fqdn) -+static krb5_error_code -+is_master_host(struct ipadb_context *ipactx, const char *fqdn, bool *result) - { -- int ret; -+ int err; - char *master_host_base = NULL; -- LDAPMessage *result = NULL; -- krb5_error_code err; -+ LDAPMessage *ldap_res = NULL; - -- ret = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s", -+ err = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s", - fqdn, ipactx->base); -- if (ret == -1) { -- return false; -- } -+ if (err == -1) -+ return ENOMEM; -+ - err = ipadb_simple_search(ipactx, master_host_base, LDAP_SCOPE_BASE, -- NULL, NULL, &result); -+ NULL, NULL, &ldap_res); - free(master_host_base); -- ldap_msgfree(result); -- if (err == 0) { -- return true; -- } -+ ldap_msgfree(ldap_res); -+ if (err != KRB5_KDB_NOENTRY && err != 0) -+ return err; -+ -+ if (result) -+ *result = err != KRB5_KDB_NOENTRY; - -- return false; -+ return 0; - } - - static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, -@@ -692,9 +694,14 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, - if ((is_host || is_service)) { - /* it is either host or service, so get the hostname first */ - char *sep = strchr(info3->base.account_name.string, '/'); -- bool is_master = is_master_host( -- ipactx, -- sep ? sep + 1 : info3->base.account_name.string); -+ bool is_master; -+ -+ ret = is_master_host(ipactx, -+ sep ? sep + 1 : info3->base.account_name.string, -+ &is_master); -+ if (ret) -+ return ret; -+ - if (is_master) { - /* Well known RID of domain controllers group */ - if (info3->base.rid == 0) { - diff --git a/SOURCES/0008-ipatests-Fix-healthcheck-report-when-nsslapd-accesslog-logbuffering-is-set-to-off_rhel#19672.patch b/SOURCES/0008-ipatests-Fix-healthcheck-report-when-nsslapd-accesslog-logbuffering-is-set-to-off_rhel#19672.patch new file mode 100644 index 0000000..f47a11f --- /dev/null +++ b/SOURCES/0008-ipatests-Fix-healthcheck-report-when-nsslapd-accesslog-logbuffering-is-set-to-off_rhel#19672.patch @@ -0,0 +1,175 @@ +From 5afda72afc6fd626359411b55f092989fdd7d82d Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Jan 15 2024 13:39:21 +0000 +Subject: ipatests: ignore nsslapd-accesslog-logbuffering WARN in healthcheck + + +Log buffering is disabled in the integration tests so we can have all +the logs at the end. This is causing a warning to show in the 389-ds +checks and causing tests to fail that expect all SUCCESS. + +Add an exclude for this specific key so tests will pass again. + +We may eventually want a more sophisiticated mechanism to handle +excludes, or updating the config in general, but this is fine for now. + +Fixes: https://pagure.io/freeipa/issue/9400 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Michal Polovka +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Michal Polovka + +--- + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 7fb8e40..14fba26 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -9,6 +9,7 @@ from __future__ import absolute_import + + from configparser import RawConfigParser, NoOptionError + from datetime import datetime, timedelta ++import io + import json + import os + import re +@@ -208,6 +209,28 @@ def run_healthcheck(host, source=None, check=None, output_type="json", + return result.returncode, data + + ++def set_excludes(host, option, value, ++ config_file='/etc/ipahealthcheck/ipahealthcheck.conf'): ++ """Mark checks that should be excluded from the results ++ ++ This will set in the [excludes] section on host: ++ option=value ++ """ ++ EXCLUDES = "excludes" ++ ++ conf = host.get_file_contents(config_file, encoding='utf-8') ++ cfg = RawConfigParser() ++ cfg.read_string(conf) ++ if not cfg.has_section(EXCLUDES): ++ cfg.add_section(EXCLUDES) ++ if not cfg.has_option(EXCLUDES, option): ++ cfg.set(EXCLUDES, option, value) ++ out = io.StringIO() ++ cfg.write(out) ++ out.seek(0) ++ host.put_file_contents(config_file, out.read()) ++ ++ + @pytest.fixture + def restart_service(): + """Shut down and restart a service as a fixture""" +@@ -265,6 +288,7 @@ class TestIpaHealthCheck(IntegrationTest): + setup_dns=True, + extra_args=['--no-dnssec-validation'] + ) ++ set_excludes(cls.master, "key", "DSCLE0004") + + def test_ipa_healthcheck_install_on_master(self): + """ +@@ -552,6 +576,7 @@ class TestIpaHealthCheck(IntegrationTest): + setup_dns=True, + extra_args=['--no-dnssec-validation'] + ) ++ set_excludes(self.replicas[0], "key", "DSCLE0004") + + # Init a user on replica to assign a DNA range + tasks.kinit_admin(self.replicas[0]) +@@ -692,6 +717,7 @@ class TestIpaHealthCheck(IntegrationTest): + 'output_type=human' + ]) + ) ++ set_excludes(self.master, "key", "DSCLE0004", config_file) + returncode, output = run_healthcheck( + self.master, failures_only=True, config=config_file + ) +@@ -707,6 +733,7 @@ class TestIpaHealthCheck(IntegrationTest): + 'output_file=%s' % HC_LOG, + ]) + ) ++ set_excludes(self.master, "key", "DSCLE0004") + returncode, _unused = run_healthcheck( + self.master, config=config_file + ) +@@ -2396,6 +2423,7 @@ class TestIpaHealthCLI(IntegrationTest): + cls.master, setup_dns=True, extra_args=['--no-dnssec-validation'] + ) + tasks.install_packages(cls.master, HEALTHCHECK_PKG) ++ set_excludes(cls.master, "key", "DSCLE0004") + + def test_indent(self): + """ +diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py +index d477c3a..b71f2d5 100644 +--- a/ipatests/test_integration/test_replica_promotion.py ++++ b/ipatests/test_integration/test_replica_promotion.py +@@ -13,7 +13,7 @@ import pytest + + from ipatests.test_integration.base import IntegrationTest + from ipatests.test_integration.test_ipahealthcheck import ( +- run_healthcheck, HEALTHCHECK_PKG ++ run_healthcheck, set_excludes, HEALTHCHECK_PKG + ) + from ipatests.pytest_ipa.integration import tasks + from ipatests.pytest_ipa.integration.tasks import ( +@@ -983,6 +983,9 @@ class TestHiddenReplicaPromotion(IntegrationTest): + # manually install KRA to verify that hidden state is synced + tasks.install_kra(cls.replicas[0]) + ++ set_excludes(cls.master, "key", "DSCLE0004") ++ set_excludes(cls.replicas[0], "key", "DSCLE0004") ++ + def _check_dnsrecords(self, hosts_expected, hosts_unexpected=()): + domain = DNSName(self.master.domain.name).make_absolute() + rset = [ + +From f1cfe7d9ff2489dbb6cad70999b0e1bd433c0537 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Jan 15 2024 13:39:21 +0000 +Subject: ipatests: fix expected output for ipahealthcheck.ipa.host + + +ipa-healthcheck commit e69589d5 changed the output when a service +keytab is missing to not report the GSSAPI error but to report +that the keytab doesn't exist at all. This distinguishes from real +Kerberos issues like kvno. + +Fixes: https://pagure.io/freeipa/issue/9482 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Michal Polovka +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Michal Polovka + +--- + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 14fba26..8aae9fa 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -629,9 +629,15 @@ class TestIpaHealthCheck(IntegrationTest): + ipahealthcheck.ipa.host when GSSAPI credentials cannot be obtained + from host's keytab. + """ +- msg = ( +- "Minor (2529639107): No credentials cache found" +- ) ++ version = tasks.get_healthcheck_version(self.master) ++ if parse_version(version) >= parse_version("0.15"): ++ msg = ( ++ "Service {service} keytab {path} does not exist." ++ ) ++ else: ++ msg = ( ++ "Minor (2529639107): No credentials cache found" ++ ) + + with tasks.FileBackup(self.master, paths.KRB5_KEYTAB): + self.master.run_command(["rm", "-f", paths.KRB5_KEYTAB]) + diff --git a/SOURCES/0008-ipatests-enable-firewall-rule-for-http-service-on-acme-client_rhbz#2230256.patch b/SOURCES/0008-ipatests-enable-firewall-rule-for-http-service-on-acme-client_rhbz#2230256.patch deleted file mode 100644 index 041905c..0000000 --- a/SOURCES/0008-ipatests-enable-firewall-rule-for-http-service-on-acme-client_rhbz#2230256.patch +++ /dev/null @@ -1,39 +0,0 @@ -From f68468718c1e01df4a9180e17d7e24d961850e19 Mon Sep 17 00:00:00 2001 -From: Mohammad Rizwan -Date: Wed, 14 Jun 2023 17:32:02 +0530 -Subject: [PATCH] ipatests: enable firewall rule for http service on acme - client - -when system hardning done i.e in case of STIG, sometimes http challanges -can't be validated by CA if port 80 is not open. This fix enable it to facilitate -the communication. - -Signed-off-by: Mohammad Rizwan -Reviewed-By: Rob Crittenden -Reviewed-By: Florence Blanc-Renaud ---- - ipatests/test_integration/test_acme.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py -index c69e810da70..414fae8d751 100644 ---- a/ipatests/test_integration/test_acme.py -+++ b/ipatests/test_integration/test_acme.py -@@ -10,6 +10,7 @@ - - from ipalib.constants import IPA_CA_RECORD - from ipatests.test_integration.base import IntegrationTest -+from ipatests.pytest_ipa.integration.firewall import Firewall - from ipatests.pytest_ipa.integration import tasks - from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup - from ipaplatform.osinfo import osinfo -@@ -82,6 +83,9 @@ def prepare_acme_client(master, client): - acme_host = f'{IPA_CA_RECORD}.{master.domain.name}' - acme_server = f'https://{acme_host}/acme/directory' - -+ # enable firewall rule on client -+ Firewall(client).enable_services(["http", "https"]) -+ - # install acme client packages - if not skip_certbot_tests: - tasks.install_packages(client, ['certbot']) diff --git a/SOURCES/0009-User-plugin-improve-error-related-to-non-existing-idp_rhbz#2224572.patch b/SOURCES/0009-User-plugin-improve-error-related-to-non-existing-idp_rhbz#2224572.patch deleted file mode 100644 index 6109658..0000000 --- a/SOURCES/0009-User-plugin-improve-error-related-to-non-existing-idp_rhbz#2224572.patch +++ /dev/null @@ -1,193 +0,0 @@ -From 99aa03413421cf2839e89e10ca279ec19233dd01 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Jul 20 2023 08:23:36 +0000 -Subject: User plugin: improve error related to non existing idp - - -The user and stageuser commands return the following error -when the user is created/updated with a non existing idp: -$ ipa user-add testuser --first test --last user --idp dummy -ipa: ERROR: no such entry - -The error is not descriptive enough and has been modified to -display instead: -$ ipa user-add testuser --first test --last user --idp dummy -ipa: ERROR: External IdP configuration dummy not found - -Fixes: https://pagure.io/freeipa/issue/9416 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden - ---- - -diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py -index 73b76d3..ba5f9b7 100644 ---- a/ipaserver/plugins/baseuser.py -+++ b/ipaserver/plugins/baseuser.py -@@ -708,7 +708,11 @@ class baseuser_mod(LDAPUpdate): - if 'ipaidpuser' not in obj_classes: - entry_attrs['objectclass'].append('ipaidpuser') - -- answer = self.api.Object['idp'].get_dn_if_exists(cl) -+ try: -+ answer = self.api.Object['idp'].get_dn_if_exists(cl) -+ except errors.NotFound: -+ reason = "External IdP configuration {} not found" -+ raise errors.NotFound(reason=_(reason).format(cl)) - entry_attrs['ipaidpconfiglink'] = answer - - # Note: we could have used the method add_missing_object_class -diff --git a/ipaserver/plugins/stageuser.py b/ipaserver/plugins/stageuser.py -index 51438a8..852e51b 100644 ---- a/ipaserver/plugins/stageuser.py -+++ b/ipaserver/plugins/stageuser.py -@@ -404,7 +404,11 @@ class stageuser_add(baseuser_add): - if 'ipaidpuser' not in entry_attrs['objectclass']: - entry_attrs['objectclass'].append('ipaidpuser') - -- answer = self.api.Object['idp'].get_dn_if_exists(cl) -+ try: -+ answer = self.api.Object['idp'].get_dn_if_exists(cl) -+ except errors.NotFound: -+ reason = "External IdP configuration {} not found" -+ raise errors.NotFound(reason=_(reason).format(cl)) - entry_attrs['ipaidpconfiglink'] = answer - - self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, -diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py -index 643b44f..a337e1f 100644 ---- a/ipaserver/plugins/user.py -+++ b/ipaserver/plugins/user.py -@@ -638,7 +638,11 @@ class user_add(baseuser_add): - if 'ipaidpuser' not in entry_attrs['objectclass']: - entry_attrs['objectclass'].append('ipaidpuser') - -- answer = self.api.Object['idp'].get_dn_if_exists(rcl) -+ try: -+ answer = self.api.Object['idp'].get_dn_if_exists(rcl) -+ except errors.NotFound: -+ reason = "External IdP configuration {} not found" -+ raise errors.NotFound(reason=_(reason).format(rcl)) - entry_attrs['ipaidpconfiglink'] = answer - - self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, - -From dbcbe9a39c99008c6858bab53e2807b7bf01ba65 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Jul 20 2023 08:23:36 +0000 -Subject: xmlrpc tests: add a test for user plugin with non-existing idp - - -Add new tests checking the error returned for -ipa user-add ... --idp nonexistingidp -ipa user-mod ... --idp nonexistingidp -ipa stageuser-add ... --idp nonexistingidp -ipa stageuser-mod ... --idp nonexistingidp - -The expected error message is: -ipa: ERROR: External IdP configuration nonexistingidp not found - -Related: https://pagure.io/freeipa/issue/9416 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden - ---- - -diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py -index 394015f..9ae5561 100644 ---- a/ipatests/test_xmlrpc/test_stageuser_plugin.py -+++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py -@@ -39,6 +39,8 @@ gid = u'456' - invalidrealm1 = u'suser1@NOTFOUND.ORG' - invalidrealm2 = u'suser1@BAD@NOTFOUND.ORG' - -+nonexistentidp = 'IdPDoesNotExist' -+ - invaliduser1 = u'+tuser1' - invaliduser2 = u'tuser1234567890123456789012345678901234567890' - invaliduser3 = u'1234' -@@ -431,6 +433,15 @@ class TestCreateInvalidAttributes(XMLRPC_test): - invalidrealm2))): - command() - -+ def test_create_invalid_idp(self, stageduser): -+ stageduser.ensure_missing() -+ command = stageduser.make_create_command( -+ options={u'ipaidpconfiglink': nonexistentidp}) -+ with raises_exact(errors.NotFound( -+ reason="External IdP configuration {} not found".format( -+ nonexistentidp))): -+ command() -+ - - @pytest.mark.tier1 - class TestUpdateInvalidAttributes(XMLRPC_test): -@@ -466,6 +477,15 @@ class TestUpdateInvalidAttributes(XMLRPC_test): - message=u'invalid \'gidnumber\': must be at least 1')): - command() - -+ def test_update_invalididp(self, stageduser): -+ stageduser.ensure_exists() -+ command = stageduser.make_update_command( -+ updates={u'ipaidpconfiglink': nonexistentidp}) -+ with raises_exact(errors.NotFound( -+ reason="External IdP configuration {} not found".format( -+ nonexistentidp))): -+ command() -+ - - @pytest.mark.tier1 - class TestActive(XMLRPC_test): -diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py -index 8ac19a4..baa2867 100644 ---- a/ipatests/test_xmlrpc/test_user_plugin.py -+++ b/ipatests/test_xmlrpc/test_user_plugin.py -@@ -86,6 +86,8 @@ expired_expiration_string = "1991-12-07T19:54:13Z" - # Date in ISO format (2013-12-10T12:00:00) - isodate_re = re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$') - -+nonexistentidp = 'IdPDoesNotExist' -+ - - @pytest.fixture(scope='class') - def user_min(request, xmlrpc_setup): -@@ -542,6 +544,18 @@ class TestUpdate(XMLRPC_test): - command() - user.delete() - -+ def test_update_invalid_idp(self, user): -+ """ Test user-mod --idp with a non-existent idp """ -+ user.ensure_exists() -+ command = user.make_update_command( -+ updates=dict(ipaidpconfiglink=nonexistentidp) -+ ) -+ with raises_exact(errors.NotFound( -+ reason="External IdP configuration {} not found".format( -+ nonexistentidp) -+ )): -+ command() -+ - - @pytest.mark.tier1 - class TestCreate(XMLRPC_test): -@@ -770,6 +784,17 @@ class TestCreate(XMLRPC_test): - user_radius.check_create(result) - user_radius.delete() - -+ def test_create_with_invalididp(self): -+ testuser = UserTracker( -+ name='idpuser', givenname='idp', sn='user', -+ ipaidpconfiglink=nonexistentidp -+ ) -+ with raises_exact(errors.NotFound( -+ reason="External IdP configuration {} not found".format( -+ nonexistentidp) -+ )): -+ testuser.create() -+ - - @pytest.mark.tier1 - class TestUserWithGroup(XMLRPC_test): - diff --git a/SOURCES/0009-kdb-PAC-generator-do-not-fail-if-canonical-principal-is-missing_rhel#23630.patch b/SOURCES/0009-kdb-PAC-generator-do-not-fail-if-canonical-principal-is-missing_rhel#23630.patch new file mode 100644 index 0000000..e37ead8 --- /dev/null +++ b/SOURCES/0009-kdb-PAC-generator-do-not-fail-if-canonical-principal-is-missing_rhel#23630.patch @@ -0,0 +1,45 @@ +From dcb9d6edc7ae4278cd552e87f644705faa13d558 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Jan 31 2024 08:31:13 +0000 +Subject: kdb: PAC generator: do not fail if canonical principal is missing + + +krbCanonicalName is mandatory for services but IPA services created +before commit e6ff83e (FreeIPA 4.4.0, ~2016) had no normalization done +to set krbCanonicalName; services created after that version were +upgraded to do have krbCanonicalName. + +Accept krbPrincipalName alone since they have no alias either */ + +Fixes: https://pagure.io/freeipa/issue/9465 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Thierry Bordaz + +--- + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 9e1431c..8035036 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -496,8 +496,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, + ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, + "krbCanonicalName", &strres); + if (ret) { +- /* krbCanonicalName is mandatory for services */ +- return ret; ++ /* krbCanonicalName is mandatory for services but IPA services ++ * created before commit e6ff83e (FreeIPA 4.4.0, ~2016) had no ++ * normalization to set krbCanonicalName; services created after ++ * that version were upgraded to do have krbCanonicalName. ++ * ++ * Accept krbPrincipalName alone since they have no alias either */ ++ ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, ++ "krbPrincipalName", &strres); ++ if (ret) ++ return ret; + } + + ret = krb5_parse_name(ipactx->kcontext, strres, &princ); + diff --git a/SOURCES/0010-Prevent-admin-user-from-being-deleted_rhbz#1921181.patch b/SOURCES/0010-Prevent-admin-user-from-being-deleted_rhbz#1921181.patch deleted file mode 100644 index be8d65f..0000000 --- a/SOURCES/0010-Prevent-admin-user-from-being-deleted_rhbz#1921181.patch +++ /dev/null @@ -1,169 +0,0 @@ -From f215d3f45396fa29bdd69f56096b50842df14908 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Aug 01 2023 22:03:03 +0000 -Subject: Prevent the admin user from being deleted - - -admin is required for trust operations - -Note that testing for removing the last member is now -irrelevant because admin must always exist so the test -for it was removed, but the code check remains. It is done -after the protected member check. - -Fixes: https://pagure.io/freeipa/issue/8878 - -Signed-off-by: Rob Crittenden -Reviewed-By: Alexander Bokovoy - ---- - -diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py -index a337e1f..6f5e349 100644 ---- a/ipaserver/plugins/user.py -+++ b/ipaserver/plugins/user.py -@@ -138,14 +138,23 @@ MEMBEROF_ADMINS = "(memberOf={})".format( - ) - - NOT_MEMBEROF_ADMINS = '(!{})'.format(MEMBEROF_ADMINS) -+PROTECTED_USERS = ('admin',) - - - def check_protected_member(user, protected_group_name=u'admins'): - ''' -- Ensure the last enabled member of a protected group cannot be deleted or -- disabled by raising LastMemberError. -+ Ensure admin and the last enabled member of a protected group cannot -+ be deleted or disabled by raising ProtectedEntryError or -+ LastMemberError as appropriate. - ''' - -+ if user in PROTECTED_USERS: -+ raise errors.ProtectedEntryError( -+ label=_("user"), -+ key=user, -+ reason=_("privileged user"), -+ ) -+ - # Get all users in the protected group - result = api.Command.user_find(in_group=protected_group_name) - -@@ -868,6 +877,12 @@ class user_mod(baseuser_mod): - - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - dn, oc = self.obj.get_either_dn(*keys, **options) -+ if options.get('rename') and keys[-1] in PROTECTED_USERS: -+ raise errors.ProtectedEntryError( -+ label=_("user"), -+ key=keys[-1], -+ reason=_("privileged user"), -+ ) - if 'objectclass' not in entry_attrs and 'rename' not in options: - entry_attrs.update({'objectclass': oc}) - self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, -diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py -index baa2867..df105a2 100644 ---- a/ipatests/test_xmlrpc/test_user_plugin.py -+++ b/ipatests/test_xmlrpc/test_user_plugin.py -@@ -978,22 +978,32 @@ class TestManagers(XMLRPC_test): - - @pytest.mark.tier1 - class TestAdmins(XMLRPC_test): -- def test_remove_original_admin(self): -- """ Try to remove the only admin """ -+ def test_delete_admin(self): -+ """ Try to delete the protected admin user """ - tracker = Tracker() -- command = tracker.make_command('user_del', [admin1]) -+ command = tracker.make_command('user_del', admin1) - -- with raises_exact(errors.LastMemberError( -- key=admin1, label=u'group', container=admin_group)): -+ with raises_exact(errors.ProtectedEntryError(label=u'user', -+ key=admin1, reason='privileged user')): -+ command() -+ -+ def test_rename_admin(self): -+ """ Try to rename the admin user """ -+ tracker = Tracker() -+ command = tracker.make_command('user_mod', admin1, -+ **dict(rename=u'newadmin')) -+ -+ with raises_exact(errors.ProtectedEntryError(label=u'user', -+ key=admin1, reason='privileged user')): - command() - - def test_disable_original_admin(self): -- """ Try to disable the only admin """ -+ """ Try to disable the original admin """ - tracker = Tracker() - command = tracker.make_command('user_disable', admin1) - -- with raises_exact(errors.LastMemberError( -- key=admin1, label=u'group', container=admin_group)): -+ with raises_exact(errors.ProtectedEntryError(label=u'user', -+ key=admin1, reason='privileged user')): - command() - - def test_create_admin2(self, admin2): -@@ -1011,21 +1021,11 @@ class TestAdmins(XMLRPC_test): - admin2.disable() - tracker = Tracker() - -- with raises_exact(errors.LastMemberError( -- key=admin1, label=u'group', container=admin_group)): -+ with raises_exact(errors.ProtectedEntryError(label=u'user', -+ key=admin1, reason='privileged user')): - tracker.run_command('user_disable', admin1) -- with raises_exact(errors.LastMemberError( -- key=admin1, label=u'group', container=admin_group)): -- tracker.run_command('user_del', admin1) - admin2.delete() - -- with raises_exact(errors.LastMemberError( -- key=admin1, label=u'group', container=admin_group)): -- tracker.run_command('user_disable', admin1) -- with raises_exact(errors.LastMemberError( -- key=admin1, label=u'group', container=admin_group)): -- tracker.run_command('user_del', admin1) -- - - @pytest.mark.tier1 - class TestPreferredLanguages(XMLRPC_test): - -From 7d62d84bdd3c2acd2f4bf70bb5fabf14c72e8ee7 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Aug 08 2023 14:50:32 +0000 -Subject: ipatests: update expected webui msg for admin deletion - - -The deletion of the admin is now forbidden (even if it is -not the last member of the admins group) and the error -message has changed from "admin cannot be deleted or -disabled because it is the last member of group admins" -to " user admin cannot be deleted/modified: privileged user". - -Update the expected message in the webui test. - -Related: https://pagure.io/freeipa/issue/8878 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Alexander Bokovoy - ---- - -diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py -index 8d44fbd..a8a92d0 100644 ---- a/ipatests/test_webui/test_user.py -+++ b/ipatests/test_webui/test_user.py -@@ -50,8 +50,7 @@ INV_FIRSTNAME = ("invalid 'first': Leading and trailing spaces are " - FIELD_REQ = 'Required field' - ERR_INCLUDE = 'may only include letters, numbers, _, -, . and $' - ERR_MISMATCH = 'Passwords must match' --ERR_ADMIN_DEL = ('admin cannot be deleted or disabled because it is the last ' -- 'member of group admins') -+ERR_ADMIN_DEL = ('user admin cannot be deleted/modified: privileged user') - USR_EXIST = 'user with name "{}" already exists' - ENTRY_EXIST = 'This entry already exists' - ACTIVE_ERR = 'active user with name "{}" already exists' - diff --git a/SOURCES/0010-ipa-kdb-Fix-memory-leak-during-PAC-verification_rhel#22644.patch b/SOURCES/0010-ipa-kdb-Fix-memory-leak-during-PAC-verification_rhel#22644.patch new file mode 100644 index 0000000..d4ba709 --- /dev/null +++ b/SOURCES/0010-ipa-kdb-Fix-memory-leak-during-PAC-verification_rhel#22644.patch @@ -0,0 +1,89 @@ +From bac601b7f35827236a106f7137f378e4888260da Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Jan 30 2024 15:17:44 +0000 +Subject: ipa-kdb: Fix memory leak during PAC verification + + +Commit 0022bd70d93708d325855d5271516d6cd894d6e8 introduced a memory leak +during the copy of some PAC buffers, because of an unfreed memory +allocation context. + +Fixes: https://pagure.io/freeipa/issue/9520 + +Signed-off-by: Julien Rische +Reviewed-By: Alexander Bokovoy + +--- + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index a18beff..9e1431c 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -2316,6 +2316,7 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context, + size_t i; + struct dom_sid *requester_sid = NULL; + struct dom_sid req_sid; ++ TALLOC_CTX *tmpctx = NULL; + + if (signing_krbtgt != NULL && + ipadb_is_cross_realm_krbtgt(signing_krbtgt->princ)) { +@@ -2371,6 +2372,12 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context, + goto done; + } + ++ tmpctx = talloc_new(NULL); ++ if (tmpctx == NULL) { ++ kerr = ENOMEM; ++ goto done; ++ } ++ + for (i = 0; i < num_buffers; i++) { + if (types[i] == KRB5_PAC_SERVER_CHECKSUM || + types[i] == KRB5_PAC_PRIVSVR_CHECKSUM || +@@ -2395,32 +2402,21 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context, + DATA_BLOB pac_attrs_data; + krb5_boolean pac_requested; + +- TALLOC_CTX *tmpctx = talloc_new(NULL); +- if (tmpctx == NULL) { +- kerr = ENOMEM; +- goto done; +- } +- + kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested); +- if (kerr != 0) { +- talloc_free(tmpctx); ++ if (kerr) + goto done; +- } + + kerr = ipadb_get_pac_attrs_blob(tmpctx, &pac_requested, &pac_attrs_data); +- if (kerr) { +- talloc_free(tmpctx); ++ if (kerr) + goto done; +- } ++ + data.magic = KV5M_DATA; + data.data = (char *)pac_attrs_data.data; + data.length = pac_attrs_data.length; + + kerr = krb5_pac_add_buffer(context, new_pac, PAC_TYPE_ATTRIBUTES_INFO, &data); +- if (kerr) { +- talloc_free(tmpctx); ++ if (kerr) + goto done; +- } + + continue; + } +@@ -2467,6 +2463,8 @@ done: + if (kerr != 0 && (new_pac != *pac)) { + krb5_pac_free(context, new_pac); + } ++ if (tmpctx) ++ talloc_free(tmpctx); + krb5_free_data_contents(context, &pac_blob); + free(types); + return kerr; + diff --git a/SOURCES/0011-Fix-memory-leak-in-the-OTP-last-token-plugin_rhbz#2227783.patch b/SOURCES/0011-Fix-memory-leak-in-the-OTP-last-token-plugin_rhbz#2227783.patch deleted file mode 100644 index 773b553..0000000 --- a/SOURCES/0011-Fix-memory-leak-in-the-OTP-last-token-plugin_rhbz#2227783.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 9438ce9207445e4ad4a9c7bdf0c9e569cabac571 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Aug 01 2023 06:07:06 +0000 -Subject: Fix memory leak in the OTP last token plugin - - -Three memory leaks are addressed: - -1. String values retrieved from the pblock need to be manually -freed. - -2. The list of objectclasses retreived from the pblock need to be -freed. - -3. Internal search results need to be freed. - -Fixes: https://pagure.io/freeipa/issue/9403 - -Signed-off-by: Rob Crittenden -Reviewed-By: Rafael Guterres Jeffman -Reviewed-By: Alexander Bokovoy - ---- - -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -index b7a2ba7..11106b2 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -@@ -54,7 +54,7 @@ void *ipa_otp_lasttoken_plugin_id; - - static bool entry_is_token(Slapi_Entry *entry) - { -- char **ocls; -+ char **ocls = NULL; - - ocls = slapi_entry_attr_get_charray(entry, SLAPI_ATTR_OBJECTCLASS); - for (size_t i = 0; ocls != NULL && ocls[i] != NULL; i++) { -@@ -64,6 +64,7 @@ static bool entry_is_token(Slapi_Entry *entry) - } - } - -+ slapi_ch_array_free(ocls); - return false; - } - -@@ -138,7 +139,8 @@ static bool is_pwd_enabled(const char *user_dn) - static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry) - { - Slapi_DN *target_sdn = NULL; -- const char *bind_dn; -+ char *bind_dn; -+ bool rv = false; - - /* Ignore internal operations. */ - if (slapi_op_internal(pb)) -@@ -147,23 +149,35 @@ static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry) - /* Load parameters. */ - (void) slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn); - (void) slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn); -- if (target_sdn == NULL || bind_dn == NULL) { -- LOG_FATAL("Missing parameters!\n"); -- return false; -+ if (bind_dn == NULL) { -+ LOG_FATAL("bind_dn parameter missing!\n"); -+ goto done; -+ } -+ if (target_sdn == NULL) { -+ LOG_FATAL("target_sdn parameter missing!\n"); -+ goto done; - } - - if (entry != NULL - ? !entry_is_token(entry) -- : !sdn_in_otp_container(target_sdn)) -- return true; -+ : !sdn_in_otp_container(target_sdn)) { -+ rv = true; -+ goto done; -+ } - -- if (!sdn_is_only_enabled_token(target_sdn, bind_dn)) -- return true; -+ if (!sdn_is_only_enabled_token(target_sdn, bind_dn)) { -+ rv = true; -+ goto done; -+ } - -- if (is_pwd_enabled(bind_dn)) -- return true; -+ if (is_pwd_enabled(bind_dn)) { -+ rv = true; -+ goto done; -+ } - -- return false; -+done: -+ slapi_ch_free_string(&bind_dn); -+ return rv; - } - - static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr) -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c -index a3cbfb0..4be4ede 100644 ---- a/daemons/ipa-slapi-plugins/libotp/otp_token.c -+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c -@@ -398,6 +398,7 @@ static struct otp_token **find(const struct otp_config *cfg, const char *user_dn - } - - error: -+ slapi_free_search_results_internal(pb); - slapi_pblock_destroy(pb); - return tokens; - } - diff --git a/SOURCES/0011-Fix-session-cookie-access_rhel#23622.patch b/SOURCES/0011-Fix-session-cookie-access_rhel#23622.patch new file mode 100644 index 0000000..87a33f0 --- /dev/null +++ b/SOURCES/0011-Fix-session-cookie-access_rhel#23622.patch @@ -0,0 +1,238 @@ +From 381af470779ea87335f57038dcbe72cd042ae6bb Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Jan 30 2024 15:11:05 +0000 +Subject: ipapython: Clean up krb5_error + + +`krb5_error` has different definition in MIT krb. +https://web.mit.edu/kerberos/krb5-latest/doc/appdev/refs/types/krb5_error.html + +> Error message structure. +> +> Declaration: +> typedef struct _krb5_error krb5_error + +While `krb5_error_code` +https://web.mit.edu/kerberos/www/krb5-latest/doc/appdev/refs/types/krb5_error_code.html#c.krb5_error_code + +> krb5_error_code +> Used to convey an operation status. +> +> The value 0 indicates success; any other values are com_err codes. Use krb5_get_error_message() to obtain a string describing the error. +> +> Declaration +> typedef krb5_int32 krb5_error_code + +And this is what was actually used. + +To prevent confusion of types `krb5_error` was replaced with +`krb5_error_code`. + +Fixes: https://pagure.io/freeipa/issue/9519 +Signed-off-by: Stanislav Levin +Reviewed-By: Alexander Bokovoy + +--- + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index c43ef7d..371cf15 100644 +--- a/ipapython/session_storage.py ++++ b/ipapython/session_storage.py +@@ -111,7 +111,7 @@ class KRB5Error(Exception): + + + def krb5_errcheck(result, func, arguments): +- """Error checker for krb5_error return value""" ++ """Error checker for krb5_error_code return value""" + if result != 0: + raise KRB5Error(result, func.__name__, arguments) + +@@ -119,14 +119,13 @@ def krb5_errcheck(result, func, arguments): + krb5_context = ctypes.POINTER(_krb5_context) + krb5_ccache = ctypes.POINTER(_krb5_ccache) + krb5_data_p = ctypes.POINTER(_krb5_data) +-krb5_error = ctypes.c_int32 + krb5_creds = _krb5_creds + krb5_pointer = ctypes.c_void_p + krb5_cc_cursor = krb5_pointer + + krb5_init_context = LIBKRB5.krb5_init_context + krb5_init_context.argtypes = (ctypes.POINTER(krb5_context), ) +-krb5_init_context.restype = krb5_error ++krb5_init_context.restype = krb5_error_code + krb5_init_context.errcheck = krb5_errcheck + + krb5_free_context = LIBKRB5.krb5_free_context +@@ -143,30 +142,30 @@ krb5_free_data_contents.restype = None + + krb5_cc_default = LIBKRB5.krb5_cc_default + krb5_cc_default.argtypes = (krb5_context, ctypes.POINTER(krb5_ccache), ) +-krb5_cc_default.restype = krb5_error ++krb5_cc_default.restype = krb5_error_code + krb5_cc_default.errcheck = krb5_errcheck + + krb5_cc_close = LIBKRB5.krb5_cc_close + krb5_cc_close.argtypes = (krb5_context, krb5_ccache, ) +-krb5_cc_close.restype = krb5_error ++krb5_cc_close.restype = krb5_error_code + krb5_cc_close.errcheck = krb5_errcheck + + krb5_parse_name = LIBKRB5.krb5_parse_name + krb5_parse_name.argtypes = (krb5_context, ctypes.c_char_p, + ctypes.POINTER(krb5_principal), ) +-krb5_parse_name.restype = krb5_error ++krb5_parse_name.restype = krb5_error_code + krb5_parse_name.errcheck = krb5_errcheck + + krb5_cc_set_config = LIBKRB5.krb5_cc_set_config + krb5_cc_set_config.argtypes = (krb5_context, krb5_ccache, krb5_principal, + ctypes.c_char_p, krb5_data_p, ) +-krb5_cc_set_config.restype = krb5_error ++krb5_cc_set_config.restype = krb5_error_code + krb5_cc_set_config.errcheck = krb5_errcheck + + krb5_cc_get_principal = LIBKRB5.krb5_cc_get_principal + krb5_cc_get_principal.argtypes = (krb5_context, krb5_ccache, + ctypes.POINTER(krb5_principal), ) +-krb5_cc_get_principal.restype = krb5_error ++krb5_cc_get_principal.restype = krb5_error_code + krb5_cc_get_principal.errcheck = krb5_errcheck + + # krb5_build_principal is a variadic function but that can't be expressed +@@ -177,26 +176,26 @@ krb5_build_principal.argtypes = (krb5_context, ctypes.POINTER(krb5_principal), + ctypes.c_uint, ctypes.c_char_p, + ctypes.c_char_p, ctypes.c_char_p, + ctypes.c_char_p, ctypes.c_char_p, ) +-krb5_build_principal.restype = krb5_error ++krb5_build_principal.restype = krb5_error_code + krb5_build_principal.errcheck = krb5_errcheck + + krb5_cc_start_seq_get = LIBKRB5.krb5_cc_start_seq_get + krb5_cc_start_seq_get.argtypes = (krb5_context, krb5_ccache, + ctypes.POINTER(krb5_cc_cursor), ) +-krb5_cc_start_seq_get.restype = krb5_error ++krb5_cc_start_seq_get.restype = krb5_error_code + krb5_cc_start_seq_get.errcheck = krb5_errcheck + + krb5_cc_next_cred = LIBKRB5.krb5_cc_next_cred + krb5_cc_next_cred.argtypes = (krb5_context, krb5_ccache, + ctypes.POINTER(krb5_cc_cursor), + ctypes.POINTER(krb5_creds), ) +-krb5_cc_next_cred.restype = krb5_error ++krb5_cc_next_cred.restype = krb5_error_code + krb5_cc_next_cred.errcheck = krb5_errcheck + + krb5_cc_end_seq_get = LIBKRB5.krb5_cc_end_seq_get + krb5_cc_end_seq_get.argtypes = (krb5_context, krb5_ccache, + ctypes.POINTER(krb5_cc_cursor), ) +-krb5_cc_end_seq_get.restype = krb5_error ++krb5_cc_end_seq_get.restype = krb5_error_code + krb5_cc_end_seq_get.errcheck = krb5_errcheck + + krb5_free_cred_contents = LIBKRB5.krb5_free_cred_contents +@@ -212,7 +211,7 @@ krb5_principal_compare.restype = krb5_boolean + krb5_unparse_name = LIBKRB5.krb5_unparse_name + krb5_unparse_name.argtypes = (krb5_context, krb5_principal, + ctypes.POINTER(ctypes.c_char_p), ) +-krb5_unparse_name.restype = krb5_error ++krb5_unparse_name.restype = krb5_error_code + krb5_unparse_name.errcheck = krb5_errcheck + + krb5_free_unparsed_name = LIBKRB5.krb5_free_unparsed_name + +From 2a4bad8bb3295c5c0f5a760ecd41871c4c5a0c56 Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Jan 30 2024 15:11:05 +0000 +Subject: ipapython: Correct return type of krb5_free_cred_contents + + +According to https://web.mit.edu/kerberos/krb5-latest/doc/appdev/refs/api/krb5_free_cred_contents.html + +> krb5_free_cred_contents - Free the contents of a krb5_creds structure. +> +> void krb5_free_cred_contents(krb5_context context, krb5_creds * val) +> param: +> [in] context - Library context +> +> [in] val - Credential structure to free contents of +> +> This function frees the contents of val , but not the structure itself. + +https://github.com/krb5/krb5/blob/5b00197227231943bd2305328c8260dd0b0dbcf0/src/lib/krb5/krb/kfree.c#L166 + +This leads to undefined behavior and `krb5_free_cred_contents` can +raise KRB5Error (because of garbage data) while actually its foreign +function doesn't. + +Fixes: https://pagure.io/freeipa/issue/9519 +Signed-off-by: Stanislav Levin +Reviewed-By: Alexander Bokovoy + +--- + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index 371cf15..dc36f54 100644 +--- a/ipapython/session_storage.py ++++ b/ipapython/session_storage.py +@@ -200,8 +200,7 @@ krb5_cc_end_seq_get.errcheck = krb5_errcheck + + krb5_free_cred_contents = LIBKRB5.krb5_free_cred_contents + krb5_free_cred_contents.argtypes = (krb5_context, ctypes.POINTER(krb5_creds)) +-krb5_free_cred_contents.restype = krb5_error +-krb5_free_cred_contents.errcheck = krb5_errcheck ++krb5_free_cred_contents.restype = None + + krb5_principal_compare = LIBKRB5.krb5_principal_compare + krb5_principal_compare.argtypes = (krb5_context, krb5_principal, + +From beb402afdbf32c01eed860e9416356f7b492ad74 Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Jan 30 2024 15:11:05 +0000 +Subject: ipapython: Propagate KRB5Error exceptions on iterating ccache + + +`ipapython.session_storage.get_data` iterates over +credentials in a credential cache till `krb5_cc_next_cred` returns +an error. This function doesn't expect any error on calling +other kerberos foreign functions during iteration. But that can +actually happen and KRB5Error exceptions stop an iteration while +they should be propagated. + +With this change iteration will exactly stop on `krb5_cc_next_cred` +error as it was supposed to be. + +Fixes: https://pagure.io/freeipa/issue/9519 +Signed-off-by: Stanislav Levin +Reviewed-By: Alexander Bokovoy + +--- + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index dc36f54..e890dc9 100644 +--- a/ipapython/session_storage.py ++++ b/ipapython/session_storage.py +@@ -312,8 +312,12 @@ def get_data(princ_name, key): + checkcreds = krb5_creds() + # the next function will throw an error and break out of the + # while loop when we try to access past the last cred +- krb5_cc_next_cred(context, ccache, ctypes.byref(cursor), +- ctypes.byref(checkcreds)) ++ try: ++ krb5_cc_next_cred(context, ccache, ctypes.byref(cursor), ++ ctypes.byref(checkcreds)) ++ except KRB5Error: ++ break ++ + if (krb5_principal_compare(context, principal, + checkcreds.client) == 1 and + krb5_principal_compare(context, srv_princ, +@@ -328,8 +332,6 @@ def get_data(princ_name, key): + else: + krb5_free_cred_contents(context, + ctypes.byref(checkcreds)) +- except KRB5Error: +- pass + finally: + krb5_cc_end_seq_get(context, ccache, ctypes.byref(cursor)) + + diff --git a/SOURCES/0012-Do-not-ignore-staged-users-in-sidgen-plugin_rhel#23626.patch b/SOURCES/0012-Do-not-ignore-staged-users-in-sidgen-plugin_rhel#23626.patch new file mode 100644 index 0000000..b5eb5be --- /dev/null +++ b/SOURCES/0012-Do-not-ignore-staged-users-in-sidgen-plugin_rhel#23626.patch @@ -0,0 +1,109 @@ +From b56a80581ef388e19d5761020454e51463036cd6 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 23 Jan 2024 14:47:50 +0200 +Subject: [PATCH] sidgen: ignore staged users when generating SIDs + +Staged users have + + uidNumber: -1 + gidNumber: -1 + ipaUniqueID: autogenerate + +We cannot generate ipaSecurityIdentifier based on those UID/GID numbers. +However, '-1' value will trigger an error + + find_sid_for_ldap_entry - [file ipa_sidgen_common.c, line 483]: ID value too large. + +And that, in turn, will cause stopping SID generation for all users. + +Detect 'ipaUniqueID: autogenerate' situation and ignore these entries. + +Fixes: https://pagure.io/freeipa/issue/9517 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Thierry Bordaz +--- + daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h | 2 ++ + .../ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c | 12 ++++++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h +index 0feff7eec..bd46982d0 100644 +--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h ++++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h +@@ -45,6 +45,8 @@ + #define UID_NUMBER "uidnumber" + #define GID_NUMBER "gidnumber" + #define IPA_SID "ipantsecurityidentifier" ++#define IPA_UNIQUEID "ipauniqueid" ++#define IPA_UNIQUEID_AUTOGENERATE "autogenerate" + #define DOM_ATTRS_FILTER OBJECTCLASS"=ipantdomainattrs" + #define DOMAIN_ID_RANGE_FILTER OBJECTCLASS"=ipadomainidrange" + #define POSIX_ACCOUNT "posixaccount" +diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c +index 6f784804c..cb763ebf8 100644 +--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c ++++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c +@@ -454,6 +454,7 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry, + uint32_t id; + char *sid = NULL; + char **objectclasses = NULL; ++ char *uniqueid = NULL; + Slapi_PBlock *mod_pb = NULL; + Slapi_Mods *smods = NULL; + int result; +@@ -479,6 +480,16 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry, + goto done; + } + ++ uniqueid = slapi_entry_attr_get_charptr(entry, IPA_UNIQUEID); ++ if (uniqueid != NULL && ++ strncmp(IPA_UNIQUEID_AUTOGENERATE, uniqueid, ++ sizeof(IPA_UNIQUEID_AUTOGENERATE)) == 0) { ++ LOG("Staged entry [%s] does not have Posix IDs, nothing to do.\n", ++ dn_str); ++ ret = 0; ++ goto done; ++ } ++ + if (uid_number >= UINT32_MAX || gid_number >= UINT32_MAX) { + LOG_FATAL("ID value too large.\n"); + ret = LDAP_CONSTRAINT_VIOLATION; +@@ -554,6 +565,7 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry, + } + + done: ++ slapi_ch_free_string(&uniqueid); + slapi_ch_free_string(&sid); + slapi_pblock_destroy(mod_pb); + slapi_mods_free(&smods); +-- +2.43.0 + +From 07150b71537744f491d022c737ef04775c72a10a Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 23 Jan 2024 14:53:39 +0200 +Subject: [PATCH] sidgen: fix missing prototypes + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Thierry Bordaz +--- + daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h +index bd46982d0..aec862796 100644 +--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h ++++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h +@@ -106,3 +106,6 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry, + const char *base_dn, + const char *dom_sid, + struct range_info **ranges); ++ ++int sidgen_task_init(Slapi_PBlock *pb); ++int ipa_sidgen_init(Slapi_PBlock *pb); +-- +2.43.0 + diff --git a/SOURCES/0012-ipatests-fix-test_topology_rhbz#2232351.patch b/SOURCES/0012-ipatests-fix-test_topology_rhbz#2232351.patch deleted file mode 100644 index e5533c3..0000000 --- a/SOURCES/0012-ipatests-fix-test_topology_rhbz#2232351.patch +++ /dev/null @@ -1,58 +0,0 @@ -From fdaad3a45f5674876fd3f6cc7ad1e916ebfc7080 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Aug 14 2023 13:02:20 +0000 -Subject: ipatests: fix test_topology - - -The test TestTopologyOptions::test_add_remove_segment is -randomly failing downstream. Test scenario: -- create a line topology master <-> repl1 <-> repl2 -- create user on master -- wait for repl success on master -- check that the user is seen on repl2 - -The test waits for replication to complete on the master but -it should also wait for the replication to complete on repl1 -before checking the user presence on repl2. - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Anuja More - ---- - -diff --git a/ipatests/test_integration/test_topology.py b/ipatests/test_integration/test_topology.py -index 8a240fa..618c9d5 100644 ---- a/ipatests/test_integration/test_topology.py -+++ b/ipatests/test_integration/test_topology.py -@@ -124,6 +124,9 @@ class TestTopologyOptions(IntegrationTest): - self.replicas[0], - self.replicas[1]) - assert err == "", err -+ # At this point we have replicas[1] <-> master <-> replicas[0] -+ # ^--------------------------^ -+ - # Make sure the new segment is shown by `ipa topologysegment-find` - result1 = self.master.run_command(['ipa', 'topologysegment-find', - DOMAIN_SUFFIX_NAME]).stdout_text -@@ -137,9 +140,12 @@ class TestTopologyOptions(IntegrationTest): - deleteme = find_segment(self.master, self.replicas[1]) - returncode, error = tasks.destroy_segment(self.master, deleteme) - assert returncode == 0, error -+ # At this point we have master <-> replicas[0] <-> replicas[1] -+ - # Wait till replication ends and make sure replica1 does not have - # segment that was deleted on master - master_ldap = self.master.ldap_connect() -+ repl_ldap = self.replicas[0].ldap_connect() - tasks.wait_for_replication(master_ldap) - result3 = self.replicas[0].run_command(['ipa', 'topologysegment-find', - DOMAIN_SUFFIX_NAME]).stdout_text -@@ -150,6 +156,7 @@ class TestTopologyOptions(IntegrationTest): - '--first', 'test', - '--last', 'user']) - tasks.wait_for_replication(master_ldap) -+ tasks.wait_for_replication(repl_ldap) - result4 = self.replicas[1].run_command(['ipa', 'user-find']) - assert('someuser' in result4.stdout_text), 'User not found: someuser' - # We end up having a line topology: master <-> replica1 <-> replica2 - diff --git a/SOURCES/0013-Installer-activate-nss-and-pam-services-in-sssd.conf_rhbz#2216532.patch b/SOURCES/0013-Installer-activate-nss-and-pam-services-in-sssd.conf_rhbz#2216532.patch deleted file mode 100644 index 64a634c..0000000 --- a/SOURCES/0013-Installer-activate-nss-and-pam-services-in-sssd.conf_rhbz#2216532.patch +++ /dev/null @@ -1,40 +0,0 @@ -From f38eefd9f7e54470de7c707782114b17aac8762a Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Aug 16 2023 15:25:34 +0000 -Subject: Installer: activate nss and pam services in sssd.conf - - -If there is already a sssd.conf file before the installer is -executed, the nss and pam services may not be enabled by the -installer. This happens for instance if the machine is hardened -for STIG and sssd.conf does not define services=... in the -[sssd] section. - -The consequence is that trust cannot be established with an AD -domain. - -The installer must enable nss and pam services even if there is -a pre-existing sssd.conf file. - -Fixes: https://pagure.io/freeipa/issue/9427 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Alexander Bokovoy - ---- - -diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py -index ef29a2c..07d62a7 100644 ---- a/ipaclient/install/client.py -+++ b/ipaclient/install/client.py -@@ -969,6 +969,9 @@ def configure_sssd_conf( - nss_service.set_option('memcache_timeout', 600) - sssdconfig.save_service(nss_service) - -+ sssd_enable_service(sssdconfig, 'nss') -+ sssd_enable_service(sssdconfig, 'pam') -+ - domain.set_option('ipa_domain', cli_domain) - domain.set_option('ipa_hostname', client_hostname) - if cli_domain.lower() != cli_realm.lower(): - diff --git a/SOURCES/0013-ipa-kdb-Disable-Bronze-Bit-check-if-PAC-not-available_rhel#22313.patch b/SOURCES/0013-ipa-kdb-Disable-Bronze-Bit-check-if-PAC-not-available_rhel#22313.patch new file mode 100644 index 0000000..14aa1e0 --- /dev/null +++ b/SOURCES/0013-ipa-kdb-Disable-Bronze-Bit-check-if-PAC-not-available_rhel#22313.patch @@ -0,0 +1,310 @@ +From 67ca47ba4092811029eec02f8af9c34ba7662924 Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Mon, 9 Oct 2023 15:47:03 +0200 +Subject: [PATCH] ipa-kdb: Ensure Bronze-Bit check can be enabled + +MIT krb5 1.19 and older do not implement support for PAC ticket +signature to protect the encrypted part of tickets. This is the cause of +the Bronze-Bit vulnerability (CVE-2020-17043). The Bronze-Bit attack +detection mechanism introduced in a847e248 relies on the content of the +PAC. + +However, since CVE-2022-37967, the content of the PAC can no longer be +trusted if the KDC does not support PAC extended KDC signature (aka. +PAC full checksum). This signature is supported in MIT krb5 since +version 1.21. + +Support for the PAC extended KDC signature was backported downstream to +krb5 1.18.2 for CentOS 8 Stream (dist-git commit 7d215a54). This makes +the content of the PAC still trustworthy there. + +This commit disables the Bronze-Bit attack detection mechanism at build +time in case krb5 does not provide the krb5_pac_full_sign_compat() +function. + +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb.h | 4 ++++ + daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 7 +++++++ + daemons/ipa-kdb/ipa_kdb_mspac.c | 4 ++++ + 3 files changed, 15 insertions(+) + +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 02b2cb631..c6926f7d5 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -367,6 +367,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + const char *test_realm, size_t size, + char **trusted_realm); + ++#if KRB5_KDB_DAL_MAJOR_VERSION <= 8 ++# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + /* Try to detect a Bronze-Bit attack based on the content of the request and + * data from the KDB. + * +@@ -379,6 +381,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + krb5_error_code + ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, + bool *detected, const char **status); ++# endif ++#endif + + /* DELEGATION CHECKS */ + +diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +index 1032dff0b..ee0546c01 100644 +--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +@@ -185,11 +185,18 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata, + const char **status, krb5_deltat *lifetime_out, + krb5_deltat *renew_lifetime_out) + { ++#if KRB5_KDB_DAL_MAJOR_VERSION <= 8 ++# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + krb5_error_code kerr; + + kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status); + if (kerr) + return KRB5KDC_ERR_POLICY; ++# else ++# warning Support for Kerberos PAC extended KDC signature is missing.\ ++ This makes FreeIPA vulnerable to the Bronze-Bit exploit (CVE-2020-17049). ++# endif ++#endif + + *status = NULL; + *lifetime_out = 0; +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index b4e22d431..05d5b407d 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3299,6 +3299,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + return KRB5_KDB_NOENTRY; + } + ++#if KRB5_KDB_DAL_MAJOR_VERSION <= 8 ++# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + krb5_error_code + ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, + bool *detected, const char **status) +@@ -3471,3 +3473,5 @@ end: + ipadb_free_principal(context, proxy_entry); + return kerr; + } ++# endif ++#endif +-- +2.43.0 + +From 27b96c17dd51d076e04d97662b7c788658a5094a Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Jan 26 2024 09:35:57 +0000 +Subject: ipa-kdb: Disable Bronze-Bit check if PAC not available + + +The Bronze-Bit check introduced in commit +a847e2483b4c4832ee5129901da169f4eb0d1392 requires the MS-PAC to be +present in the evidence ticket in order for S4U2Proxy requests to be +accepted. This actually requires SIDs to be set. + +However, domains that were initialized before commit +e527857d000e558b3288a7a210400abaf2171237 may still not have SIDs +configured. This would results in all S4U2Proxy requests to fail +(including all the HTTP API requests). + +This present commit disables the check for the Bronze-Bit exploit +(CVE-2020-17049) in case the domain is not able to generate PACs. +Instead, it prints a warning message in the KDC logs each time a +S4U2Proxy request is processed. + +Fixes: https://pagure.io/freeipa/issue/9521 + +Signed-off-by: Julien Rische +Reviewed-By: Alexander Bokovoy + +--- + +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index c6926f7..621c235 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -370,17 +370,21 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + #if KRB5_KDB_DAL_MAJOR_VERSION <= 8 + # ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + /* Try to detect a Bronze-Bit attack based on the content of the request and +- * data from the KDB. ++ * data from the KDB. This check will work only if the domain supports MS-PAC. + * + * context krb5 context + * request KDB request +- * detected Set to "true" if a bronze bit attack is detected and the +- * pointer is not NULL. Remains unset otherwise. ++ * supported If not NULL, set to "false" in case the Bronze-Bit exploit ++ * detection process silently failed to complete because the ++ * domain does not meet requirements. Set to "true" otherwise. ++ * detected If not NULL, set to "true" if a Bronze-Bit attack is detected. ++ * Set to "false" otherwise. + * status If the call fails and the pointer is not NULL, set it with a + * message describing the cause of the failure. */ + krb5_error_code + ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, +- bool *detected, const char **status); ++ bool *supported, bool *detected, ++ const char **status); + # endif + #endif + +diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +index ee0546c..713e9a0 100644 +--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +@@ -188,10 +188,18 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata, + #if KRB5_KDB_DAL_MAJOR_VERSION <= 8 + # ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + krb5_error_code kerr; ++ bool supported; + +- kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status); ++ kerr = ipadb_check_for_bronze_bit_attack(context, request, supported, NULL, ++ status); + if (kerr) + return KRB5KDC_ERR_POLICY; ++ ++ if (!supported) ++ krb5_klog_syslog(LOG_WARNING, "MS-PAC not available. This makes " ++ "FreeIPA vulnerable to the Bronze-Bit exploit " ++ "(CVE-2020-17049). Please generate SIDs to enable " ++ "PAC support."); + # else + # warning Support for Kerberos PAC extended KDC signature is missing.\ + This makes FreeIPA vulnerable to the Bronze-Bit exploit (CVE-2020-17049). +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 05d5b40..a18beff 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3303,11 +3303,14 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + # ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + krb5_error_code + ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, +- bool *detected, const char **status) ++ bool *supported, bool *detected, ++ const char **status) + { + krb5_error_code kerr; + const char *st = NULL; + size_t i, j; ++ bool in_supported = true, in_detected = false; ++ struct ipadb_context *ipactx; + krb5_ticket *evidence_tkt; + krb5_authdata **authdata, **ifrel = NULL; + krb5_pac pac = NULL; +@@ -3327,6 +3330,21 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, + goto end; + } + ++ ipactx = ipadb_get_context(context); ++ if (!ipactx) { ++ kerr = KRB5_KDB_DBNOTINITED; ++ goto end; ++ } ++ ++ /* Handle the case where the domain is not able to generate PACs (probably ++ * because SIDs are not set). In this case, we just skip the Bronze-Bit ++ * check. */ ++ if (!ipactx->mspac) { ++ in_supported = false; ++ kerr = 0; ++ goto end; ++ } ++ + evidence_tkt = request->second_ticket[0]; + + /* No need to check the Forwardable flag. If it was not set, this request +@@ -3451,8 +3469,7 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, + /* This evidence ticket cannot be forwardable given the privileges + * of the proxy principal. + * This is a Bronze Bit attack. */ +- if (detected) +- *detected = true; ++ in_detected = true; + st = "S4U2PROXY_BRONZE_BIT_ATTACK_DETECTED"; + kerr = EBADE; + goto end; +@@ -3464,6 +3481,10 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, + end: + if (st && status) + *status = st; ++ if (supported) ++ *supported = in_supported; ++ if (detected) ++ *detected = in_detected; + + krb5_free_authdata(context, ifrel); + krb5_pac_free(context, pac); + +From 81aa6ef695838a4b2fb5a53e773ea379a492913d Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Fri, 9 Feb 2024 16:36:03 +0100 +Subject: [PATCH] ipd-kdb: Fix some mistakes in + ipadb_check_for_bronze_bit_attack() + +Fixes: https://pagure.io/freeipa/issue/9521 +Signed-off-by: Julien Rische +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb.h | 3 ++- + daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 2 +- + daemons/ipa-kdb/ipa_kdb_mspac.c | 5 +++-- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 621c23591..5de5ea7a5 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -382,7 +382,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + * status If the call fails and the pointer is not NULL, set it with a + * message describing the cause of the failure. */ + krb5_error_code +-ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, ++ipadb_check_for_bronze_bit_attack(krb5_context context, ++ const krb5_kdc_req *request, + bool *supported, bool *detected, + const char **status); + # endif +diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +index 713e9a0c8..44959f3de 100644 +--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +@@ -190,7 +190,7 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata, + krb5_error_code kerr; + bool supported; + +- kerr = ipadb_check_for_bronze_bit_attack(context, request, supported, NULL, ++ kerr = ipadb_check_for_bronze_bit_attack(context, request, &supported, NULL, + status); + if (kerr) + return KRB5KDC_ERR_POLICY; +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 80350364a..886ed7785 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3308,13 +3308,14 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + #if KRB5_KDB_DAL_MAJOR_VERSION <= 8 + # ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + krb5_error_code +-ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request, ++ipadb_check_for_bronze_bit_attack(krb5_context context, ++ const krb5_kdc_req *request, + bool *supported, bool *detected, + const char **status) + { + krb5_error_code kerr; + const char *st = NULL; +- size_t i, j; ++ size_t i, j = 0; + bool in_supported = true, in_detected = false; + struct ipadb_context *ipactx; + krb5_ticket *evidence_tkt; +-- +2.43.0 + diff --git a/SOURCES/0014-krb5kdc-Fix-start-when-pkinit-and-otp-auth-type-are-enabled_rhel#4874.patch b/SOURCES/0014-krb5kdc-Fix-start-when-pkinit-and-otp-auth-type-are-enabled_rhel#4874.patch new file mode 100644 index 0000000..e0d2386 --- /dev/null +++ b/SOURCES/0014-krb5kdc-Fix-start-when-pkinit-and-otp-auth-type-are-enabled_rhel#4874.patch @@ -0,0 +1,272 @@ +From 00f8ddbfd2795228b343e1c39c1944b44d482c18 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 11:46:19 +0200 +Subject: [PATCH 1/4] ipa-kdb: add better detection of allowed user auth type + +If default user authentication type is set to a list that does not +include a password or a hardened credential, the resulting configuration +might be incorrect for special service principals, including a krbtgt/.. +one. + +Add detection of special principals to avoid these situations and always +allow password or hardened for services. + +Special handling is needed for the following principals: + + - krbtgt/.. -- TGT service principals + - K/M -- master key principal + - kadmin/changepw -- service for changing passwords + - kadmin/kadmin -- kadmin service principal + - kadmin/history -- key used to encrypt history + +Additionally, implicitly allow password or hardened credential use for +IPA services and IPA hosts since applications typically use keytabs for +that purpose. + +Fixes: https://pagure.io/freeipa/issue/9485 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Francisco Trivino +--- + daemons/ipa-kdb/ipa_kdb.c | 62 ++++++++++++++++++++++++++++++++++----- + 1 file changed, 54 insertions(+), 8 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index 06d511c76..dbb98dba6 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -26,6 +26,7 @@ + #include "ipa_kdb.h" + #include "ipa_krb5.h" + #include "ipa_hostname.h" ++#include + + #define IPADB_GLOBAL_CONFIG_CACHE_TIME 60 + +@@ -207,6 +208,19 @@ static const struct { + { "idp", IPADB_USER_AUTH_IDP }, + { "passkey", IPADB_USER_AUTH_PASSKEY }, + { } ++}, ++ objclass_table[] = { ++ { "ipaservice", IPADB_USER_AUTH_PASSWORD }, ++ { "ipahost", IPADB_USER_AUTH_PASSWORD }, ++ { } ++}, ++ princname_table[] = { ++ { KRB5_TGS_NAME, IPADB_USER_AUTH_PASSWORD }, ++ { KRB5_KDB_M_NAME, IPADB_USER_AUTH_PASSWORD }, ++ { KADM5_ADMIN_SERVICE, IPADB_USER_AUTH_PASSWORD }, ++ { KADM5_CHANGEPW_SERVICE, IPADB_USER_AUTH_PASSWORD }, ++ { KADM5_HIST_PRINCIPAL, IPADB_USER_AUTH_PASSWORD }, ++ { } + }; + + void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le, +@@ -217,17 +231,49 @@ void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le, + + *userauth = IPADB_USER_AUTH_NONE; + vals = ldap_get_values_len(lcontext, le, IPA_USER_AUTH_TYPE); +- if (!vals) +- return; +- +- for (i = 0; vals[i]; i++) { +- for (j = 0; userauth_table[j].name; j++) { +- if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) { +- *userauth |= userauth_table[j].flag; +- break; ++ if (!vals) { ++ /* if there is no explicit ipaUserAuthType set, use objectclass */ ++ vals = ldap_get_values_len(lcontext, le, "objectclass"); ++ if (!vals) ++ return; ++ ++ for (i = 0; vals[i]; i++) { ++ for (j = 0; objclass_table[j].name; j++) { ++ if (strcasecmp(vals[i]->bv_val, objclass_table[j].name) == 0) { ++ *userauth |= objclass_table[j].flag; ++ break; ++ } ++ } ++ } ++ } else { ++ for (i = 0; vals[i]; i++) { ++ for (j = 0; userauth_table[j].name; j++) { ++ if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) { ++ *userauth |= userauth_table[j].flag; ++ break; ++ } + } + } + } ++ ++ /* If neither ipaUserAuthType nor objectClass were definitive, ++ * check the krbPrincipalName to see if it is krbtgt/ or K/M one */ ++ if (*userauth == IPADB_USER_AUTH_NONE) { ++ ldap_value_free_len(vals); ++ vals = ldap_get_values_len(lcontext, le, "krbprincipalname"); ++ if (!vals) ++ return; ++ for (i = 0; vals[i]; i++) { ++ for (j = 0; princname_table[j].name; j++) { ++ if (strncmp(vals[i]->bv_val, princname_table[j].name, ++ strlen(princname_table[j].name)) == 0) { ++ *userauth |= princname_table[j].flag; ++ break; ++ } ++ } ++ } ++ ++ } + /* If password auth is enabled, enable hardened policy too. */ + if (*userauth & IPADB_USER_AUTH_PASSWORD) { + *userauth |= IPADB_USER_AUTH_HARDENED; +-- +2.43.0 + + +From 69ae9febfb4462766b3bfe3e07e76550ece97b42 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 11:54:04 +0200 +Subject: [PATCH 2/4] ipa-kdb: when applying ticket policy, do not deny PKINIT + +PKINIT differs from other pre-authentication methods by the fact that it +can be matched indepedently of the user authentication types via certmap +plugin in KDC. + +Since PKINIT is a strong authentication method, allow its authentication +indicator and only apply the ticket policy. + +Fixes: https://pagure.io/freeipa/issue/9485 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Francisco Trivino +--- + daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +index 436ee0e62..2802221c7 100644 +--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +@@ -119,11 +119,8 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata, + pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_RADIUS]); + } else if (strcmp(auth_indicator, "pkinit") == 0) { + valid_auth_indicators++; +- if (!(ua & IPADB_USER_AUTH_PKINIT)) { +- *status = "PKINIT pre-authentication not allowed for this user."; +- kerr = KRB5KDC_ERR_POLICY; +- goto done; +- } ++ /* allow PKINIT unconditionally -- it has passed already at this ++ * point so some certificate was useful, only apply the limits */ + pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PKINIT]); + } else if (strcmp(auth_indicator, "hardened") == 0) { + valid_auth_indicators++; +-- +2.43.0 + + +From 62c44c9e69aa2721990ca3628434713e1af6f59b Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 12:20:55 +0200 +Subject: [PATCH 3/4] ipa-kdb: clarify user auth table mapping use of + _AUTH_PASSWORD + +Related: https://pagure.io/freeipa/issue/9485 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Francisco Trivino +--- + daemons/ipa-kdb/ipa_kdb.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index dbb98dba6..4e6cacf24 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -195,6 +195,9 @@ done: + return base; + } + ++/* In this table all _AUTH_PASSWORD entries will be ++ * expanded to include _AUTH_HARDENED in ipadb_parse_user_auth() ++ * which means there is no need to explicitly add it here */ + static const struct { + const char *name; + enum ipadb_user_auth flag; +-- +2.43.0 + + +From c3bc938650b19a51706d8ccd98cdf8deaa26dc28 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 13:00:48 +0200 +Subject: [PATCH 4/4] ipatests: make sure PKINIT enrollment works with a strict + policy + +Previously, for a global policy which does not include +'password', krb5kdc restart was failing. Now it should succeed. + +We set admin user authentication type to PASSWORD to simplify +configuration in the test. + +What matters here is that global policy does not include PKINIT and that +means a code in the ticket policy check will allow PKINIT implicitly +rather than explicitly. + +Related: https://pagure.io/freeipa/issue/9485 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Francisco Trivino +--- + .../test_integration/test_pkinit_install.py | 26 +++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/ipatests/test_integration/test_pkinit_install.py b/ipatests/test_integration/test_pkinit_install.py +index caa0e6a34..5c2e7af02 100644 +--- a/ipatests/test_integration/test_pkinit_install.py ++++ b/ipatests/test_integration/test_pkinit_install.py +@@ -23,6 +23,24 @@ class TestPkinitClientInstall(IntegrationTest): + def install(cls, mh): + tasks.install_master(cls.master) + ++ def enforce_password_and_otp(self): ++ """enforce otp by default and password for admin """ ++ self.master.run_command( ++ [ ++ "ipa", ++ "config-mod", ++ "--user-auth-type=otp", ++ ] ++ ) ++ self.master.run_command( ++ [ ++ "ipa", ++ "user-mod", ++ "admin", ++ "--user-auth-type=password", ++ ] ++ ) ++ + def add_certmaperule(self): + """add certmap rule to map SAN dNSName to host entry""" + self.master.run_command( +@@ -86,6 +104,14 @@ class TestPkinitClientInstall(IntegrationTest): + cabundle = self.master.get_file_contents(paths.KDC_CA_BUNDLE_PEM) + client.put_file_contents(self.tmpbundle, cabundle) + ++ def test_restart_krb5kdc(self): ++ tasks.kinit_admin(self.master) ++ self.enforce_password_and_otp() ++ self.master.run_command(['systemctl', 'stop', 'krb5kdc.service']) ++ self.master.run_command(['systemctl', 'start', 'krb5kdc.service']) ++ self.master.run_command(['systemctl', 'stop', 'kadmin.service']) ++ self.master.run_command(['systemctl', 'start', 'kadmin.service']) ++ + def test_client_install_pkinit(self): + tasks.kinit_admin(self.master) + self.add_certmaperule() +-- +2.43.0 + diff --git a/SOURCES/0015-hbactest-was-not-collecting-or-returning-messages_rhel#12780.patch b/SOURCES/0015-hbactest-was-not-collecting-or-returning-messages_rhel#12780.patch new file mode 100644 index 0000000..1adc33f --- /dev/null +++ b/SOURCES/0015-hbactest-was-not-collecting-or-returning-messages_rhel#12780.patch @@ -0,0 +1,139 @@ +From 48846e98e5e988d600ddf81c937f353fcecdea1a Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 27 Nov 2023 16:11:08 -0500 +Subject: [PATCH 1/2] hbactest was not collecting or returning messages + +hbactest does a number of internal searches, one of which +can exceed the configured sizelimit: hbacrule-find + +Collect any messages returned from thsi call and display them +to the user on the cli. + +Fixes: https://pagure.io/freeipa/issue/9486 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipaclient/plugins/hbactest.py | 2 ++ + ipaserver/plugins/hbactest.py | 14 +++++++++++--- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/ipaclient/plugins/hbactest.py b/ipaclient/plugins/hbactest.py +index 1b54530b2..e0f93b9c2 100644 +--- a/ipaclient/plugins/hbactest.py ++++ b/ipaclient/plugins/hbactest.py +@@ -38,6 +38,8 @@ class hbactest(CommandOverride): + # Note that we don't actually use --detail below to see if details need + # to be printed as our execute() method will return None for corresponding + # entries and None entries will be skipped. ++ self.log_messages(output) ++ + for o in self.output: + if o == 'value': + continue +diff --git a/ipaserver/plugins/hbactest.py b/ipaserver/plugins/hbactest.py +index 887a35b7e..568c13174 100644 +--- a/ipaserver/plugins/hbactest.py ++++ b/ipaserver/plugins/hbactest.py +@@ -24,6 +24,8 @@ from ipalib import Command, Str, Flag, Int + from ipalib import _ + from ipapython.dn import DN + from ipalib.plugable import Registry ++from ipalib.messages import VersionMissing ++ + if api.env.in_server: + try: + import ipaserver.dcerpc +@@ -323,6 +325,9 @@ class hbactest(Command): + # 2. Required options are (user, target host, service) + # 3. Options: rules to test (--rules, --enabled, --disabled), request for detail output + rules = [] ++ result = { ++ 'warning':None, 'matched':None, 'notmatched':None, 'error':None ++ } + + # Use all enabled IPA rules by default + all_enabled = True +@@ -351,8 +356,12 @@ class hbactest(Command): + + hbacset = [] + if len(testrules) == 0: +- hbacset = self.api.Command.hbacrule_find( +- sizelimit=sizelimit, no_members=False)['result'] ++ hbacrules = self.api.Command.hbacrule_find( ++ sizelimit=sizelimit, no_members=False) ++ hbacset = hbacrules['result'] ++ for message in hbacrules['messages']: ++ if message['code'] != VersionMissing.errno: ++ result.setdefault('messages', []).append(message) + else: + for rule in testrules: + try: +@@ -469,7 +478,6 @@ class hbactest(Command): + error_rules = [] + warning_rules = [] + +- result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None} + if not options['nodetail']: + # Validate runs rules one-by-one and reports failed ones + for ipa_rule in rules: +-- +2.43.0 + + +From d1e09c68af8ac77f656dd639af5d9a7f07c41f9d Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 28 Nov 2023 13:35:13 -0500 +Subject: [PATCH 2/2] ipatests: Verify that hbactest will return messages + +Limit the sizelimit of the hbactest request to confirm that +the output includes a SearchResultTruncated message. + +Fixes: https://pagure.io/freeipa/issue/9486 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipatests/test_xmlrpc/test_hbactest_plugin.py | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/ipatests/test_xmlrpc/test_hbactest_plugin.py b/ipatests/test_xmlrpc/test_hbactest_plugin.py +index 73c4ce232..e2e66c759 100644 +--- a/ipatests/test_xmlrpc/test_hbactest_plugin.py ++++ b/ipatests/test_xmlrpc/test_hbactest_plugin.py +@@ -134,6 +134,7 @@ class test_hbactest(XMLRPC_test): + assert ret['value'] + assert ret['error'] is None + assert ret['matched'] is None ++ assert 'messages' not in ret + assert ret['notmatched'] is None + + def test_c_hbactest_check_rules_enabled_detail(self): +@@ -200,7 +201,23 @@ class test_hbactest(XMLRPC_test): + nodetail=True + ) + +- def test_g_hbactest_clear_testing_data(self): ++ def test_g_hbactest_searchlimit_message(self): ++ """ ++ Test running 'ipa hbactest' with limited --sizelimit ++ ++ We know there are at least 6 rules, 4 created here + 2 default. ++ """ ++ ret = api.Command['hbactest']( ++ user=self.test_user, ++ targethost=self.test_host, ++ service=self.test_service, ++ nodetail=True, ++ sizelimit=2, ++ ) ++ ++ assert ret['messages'] is not None ++ ++ def test_h_hbactest_clear_testing_data(self): + """ + Clear data for HBAC test plugin testing. + """ +-- +2.43.0 + diff --git a/SOURCES/0016-ipatests-wait-for-replica-update-in-test_dns_locatio.patch b/SOURCES/0016-ipatests-wait-for-replica-update-in-test_dns_locatio.patch new file mode 100644 index 0000000..0a6f6b7 --- /dev/null +++ b/SOURCES/0016-ipatests-wait-for-replica-update-in-test_dns_locatio.patch @@ -0,0 +1,43 @@ +From 16a739e0260f97705827f972d53c828809dbfdb2 Mon Sep 17 00:00:00 2001 +From: Masahiro Matsuya +Date: Tue, 9 Jan 2024 23:12:11 +0900 +Subject: [PATCH] ipatests: wait for replica update in test_dns_locations + +test_ipa_ca_records and test_adtrust_system_records can fail with +NXDOMAIN, because it doesn't wait enough for the update on replica. +It can be resolved by waiting for the update with wait_for_replication. + +Fixes: https://pagure.io/freeipa/issue/9504 +Reviewed-By: Florence Blanc-Renaud +(cherry picked from commit 905a55a4ef926068630ebd2ab375f58c24dedcd1) +--- + ipatests/test_integration/test_dns_locations.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ipatests/test_integration/test_dns_locations.py b/ipatests/test_integration/test_dns_locations.py +index 44900af80..89a310892 100644 +--- a/ipatests/test_integration/test_dns_locations.py ++++ b/ipatests/test_integration/test_dns_locations.py +@@ -534,6 +534,9 @@ class TestDNSLocations(IntegrationTest): + + expected_servers = (self.master.ip, self.replicas[1].ip) + ++ ldap = self.master.ldap_connect() ++ tasks.wait_for_replication(ldap) ++ + for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip): + self._test_A_rec_against_server(ip, self.domain, expected_servers) + +@@ -557,6 +560,9 @@ class TestDNSLocations(IntegrationTest): + (self.PRIO_HIGH, self.WEIGHT, DNSName(self.master.hostname)), + ) + ++ ldap = self.master.ldap_connect() ++ tasks.wait_for_replication(ldap) ++ + for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip): + self._test_SRV_rec_against_server( + ip, self.domain, expected_servers, +-- +2.43.0 + diff --git a/SOURCES/0017-ipa-kdb-Rework-ipadb_reinit_mspac.patch b/SOURCES/0017-ipa-kdb-Rework-ipadb_reinit_mspac.patch new file mode 100644 index 0000000..b3fbfdb --- /dev/null +++ b/SOURCES/0017-ipa-kdb-Rework-ipadb_reinit_mspac.patch @@ -0,0 +1,707 @@ +From c3ac69e9cf8dfcc31ed11fc988c37bd99d3ec3cf Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Wed, 14 Feb 2024 17:47:00 +0100 +Subject: [PATCH] ipa-kdb: Rework ipadb_reinit_mspac() + +Modify ipadb_reinit_mspac() to allocate and initialize ipactx->mspac +only if all its attributes can be set. If not, ipactx->mspac is set to +NULL. This makes easier to determine if the KDC is able to generate PACs +or not. + +Also ipadb_reinit_mspac() is now able to return a status message +explaining why initialization of the PAC generator failed. This message +is printed in KDC logs. + +Fixes: https://pagure.io/freeipa/issue/9535 + +Signed-off-by: Julien Rische +Reviewed-By: Alexander Bokovoy +(cherry picked from commit 7f072e348d318e928f6270a182ca04dee8716677) +--- + daemons/ipa-kdb/ipa_kdb.c | 14 +- + daemons/ipa-kdb/ipa_kdb.h | 4 +- + daemons/ipa-kdb/ipa_kdb_mspac.c | 340 +++++++++++++----------- + daemons/ipa-kdb/ipa_kdb_mspac_private.h | 2 +- + daemons/ipa-kdb/ipa_kdb_mspac_v6.c | 5 +- + daemons/ipa-kdb/ipa_kdb_mspac_v9.c | 16 +- + daemons/ipa-kdb/ipa_kdb_principals.c | 6 +- + 7 files changed, 218 insertions(+), 169 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index 0c6325df9..fcadb8ee7 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -443,6 +443,7 @@ int ipadb_get_connection(struct ipadb_context *ipactx) + struct timeval tv = { 5, 0 }; + LDAPMessage *res = NULL; + LDAPMessage *first; ++ const char *stmsg; + int ret; + int v3; + +@@ -522,16 +523,9 @@ int ipadb_get_connection(struct ipadb_context *ipactx) + } + + /* get adtrust options using default refresh interval */ +- ret = ipadb_reinit_mspac(ipactx, false); +- if (ret && ret != ENOENT) { +- /* TODO: log that there is an issue with adtrust settings */ +- if (ipactx->lcontext == NULL) { +- /* for some reason ldap connection was reset in ipadb_reinit_mspac +- * and is no longer established => failure of ipadb_get_connection +- */ +- goto done; +- } +- } ++ ret = ipadb_reinit_mspac(ipactx, false, &stmsg); ++ if (ret && stmsg) ++ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg); + + ret = 0; + +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 5de5ea7a5..7baf4697f 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -352,7 +352,9 @@ krb5_error_code ipadb_v9_issue_pac(krb5_context context, unsigned int flags, + krb5_data ***auth_indicators); + #endif + +-krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit); ++krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, ++ bool force_reinit, ++ const char **stmsg); + + void ipadb_mspac_struct_free(struct ipadb_mspac **mspac); + krb5_error_code ipadb_check_transited_realms(krb5_context kcontext, +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 886ed7785..deed513b9 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -793,16 +793,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, + return ret; + } + ++ if (!ipactx->mspac) { ++ /* can't give a PAC without server NetBIOS name or primary group RID */ ++ return ENOENT; ++ } ++ + if (info3->base.primary_gid == 0) { + if (is_host || is_service) { + info3->base.primary_gid = 515; /* Well known RID for domain computers group */ + } else { +- if (ipactx->mspac->fallback_rid) { +- info3->base.primary_gid = ipactx->mspac->fallback_rid; +- } else { +- /* can't give a pack without a primary group rid */ +- return ENOENT; +- } ++ info3->base.primary_gid = ipactx->mspac->fallback_rid; + } + } + +@@ -812,26 +812,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, + /* always zero out, not used for Krb, only NTLM */ + memset(&info3->base.key, '\0', sizeof(info3->base.key)); + +- if (ipactx->mspac->flat_server_name) { +- info3->base.logon_server.string = +- talloc_strdup(memctx, ipactx->mspac->flat_server_name); +- if (!info3->base.logon_server.string) { +- return ENOMEM; +- } +- } else { +- /* can't give a pack without Server NetBIOS Name :-| */ +- return ENOENT; ++ info3->base.logon_server.string = ++ talloc_strdup(memctx, ipactx->mspac->flat_server_name); ++ if (!info3->base.logon_server.string) { ++ return ENOMEM; + } + +- if (ipactx->mspac->flat_domain_name) { +- info3->base.logon_domain.string = +- talloc_strdup(memctx, ipactx->mspac->flat_domain_name); +- if (!info3->base.logon_domain.string) { +- return ENOMEM; +- } +- } else { +- /* can't give a pack without Domain NetBIOS Name :-| */ +- return ENOENT; ++ info3->base.logon_domain.string = ++ talloc_strdup(memctx, ipactx->mspac->flat_domain_name); ++ if (!info3->base.logon_domain.string) { ++ return ENOMEM; + } + + if (is_host || is_service) { +@@ -1044,6 +1034,11 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext, + return KRB5_KDB_DBNOTINITED; + } + ++ /* Check if PAC generator is initialized */ ++ if (!ipactx->mspac) { ++ return ENOENT; ++ } ++ + ied = (struct ipadb_e_data *)client->e_data; + if (ied->magic != IPA_E_DATA_MAGIC) { + return EINVAL; +@@ -1626,14 +1621,14 @@ static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context, + { + struct ipadb_context *ipactx; + struct ipadb_adtrusts *domain; +- int i; ++ size_t i; + + ipactx = ipadb_get_context(context); + if (!ipactx) { + return NULL; + } + +- if (ipactx->mspac == NULL) { ++ if (!ipactx->mspac) { + return NULL; + } + +@@ -1655,6 +1650,7 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context, + { + struct ipadb_context *ipactx; + struct ipadb_adtrusts *domain; ++ const char *stmsg = NULL; + krb5_error_code kerr; + + ipactx = ipadb_get_context(context); +@@ -1663,8 +1659,10 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context, + } + + /* re-init MS-PAC info using default update interval */ +- kerr = ipadb_reinit_mspac(ipactx, false); ++ kerr = ipadb_reinit_mspac(ipactx, false, &stmsg); + if (kerr != 0) { ++ if (stmsg) ++ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg); + return NULL; + } + domain = get_domain_from_realm(context, realm); +@@ -1717,6 +1715,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context, + struct ipadb_e_data *ied = NULL; + int flags = 0; + struct dom_sid client_sid; ++ const char *stmsg = NULL; + #ifdef KRB5_KDB_FLAG_ALIAS_OK + flags = KRB5_KDB_FLAG_ALIAS_OK; + #endif +@@ -1730,10 +1729,14 @@ static krb5_error_code check_logon_info_consistent(krb5_context context, + * check that our own view on the PAC details is up to date */ + if (ipactx->mspac->domsid.num_auths == 0) { + /* Force re-init of KDB's view on our domain */ +- kerr = ipadb_reinit_mspac(ipactx, true); ++ kerr = ipadb_reinit_mspac(ipactx, true, &stmsg); + if (kerr != 0) { +- krb5_klog_syslog(LOG_ERR, +- "PAC issue: unable to update realm's view on PAC info"); ++ if (stmsg) { ++ krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg); ++ } else { ++ krb5_klog_syslog(LOG_ERR, "PAC issue: unable to update " \ ++ "realm's view on PAC info"); ++ } + return KRB5KDC_ERR_POLICY; + } + } +@@ -1746,7 +1749,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context, + if (is_s4u && (ipactx->mspac->trusts != NULL)) { + /* Iterate through list of trusts and check if this SID belongs to + * one of the domains we trust */ +- for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) { ++ for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) { + result = dom_sid_check(&ipactx->mspac->trusts[i].domsid, + info->info->info3.base.domain_sid, true); + if (result) { +@@ -1858,11 +1861,11 @@ krb5_error_code filter_logon_info(krb5_context context, + struct ipadb_mspac *mspac_ctx = ipactx->mspac; + result = FALSE; + /* Didn't match but perhaps the original PAC was issued by a child domain's DC? */ +- for (k = 0; k < mspac_ctx->num_trusts; k++) { +- result = dom_sid_check(&mspac_ctx->trusts[k].domsid, ++ for (size_t m = 0; m < mspac_ctx->num_trusts; m++) { ++ result = dom_sid_check(&mspac_ctx->trusts[m].domsid, + info->info->info3.base.domain_sid, true); + if (result) { +- domain = &mspac_ctx->trusts[k]; ++ domain = &mspac_ctx->trusts[m]; + break; + } + } +@@ -2091,10 +2094,10 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context, + return KRB5_KDB_DBNOTINITED; + } + /* In S4U case we might be dealing with the PAC issued by the trusted domain */ +- if ((ipactx->mspac->trusts != NULL)) { ++ if (ipactx->mspac->trusts) { + /* Iterate through list of trusts and check if this SID belongs to + * one of the domains we trust */ +- for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) { ++ for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) { + result = dom_sid_check(&ipactx->mspac->trusts[i].domsid, + &client_sid, false); + if (result) { +@@ -2631,7 +2634,7 @@ static char *get_server_netbios_name(struct ipadb_context *ipactx) + + void ipadb_mspac_struct_free(struct ipadb_mspac **mspac) + { +- int i, j; ++ size_t i, j; + + if (!*mspac) return; + +@@ -2786,7 +2789,8 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx) + LDAPDN dn = NULL; + char **sid_blocklist_incoming = NULL; + char **sid_blocklist_outgoing = NULL; +- int ret, n, i; ++ size_t i, n; ++ int ret; + + ret = asprintf(&base, "cn=ad,cn=trusts,%s", ipactx->base); + if (ret == -1) { +@@ -2871,7 +2875,7 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx) + + t[n].upn_suffixes_len = NULL; + if (t[n].upn_suffixes != NULL) { +- int len = 0; ++ size_t len = 0; + + for (; t[n].upn_suffixes[len] != NULL; len++); + +@@ -2986,108 +2990,114 @@ done: + return ret; + } + +-krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit) ++krb5_error_code ++ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit, ++ const char **stmsg) + { + char *dom_attrs[] = { "ipaNTFlatName", + "ipaNTFallbackPrimaryGroup", + "ipaNTSecurityIdentifier", + NULL }; + char *grp_attrs[] = { "ipaNTSecurityIdentifier", NULL }; +- krb5_error_code kerr; + LDAPMessage *result = NULL; + LDAPMessage *lentry; +- struct dom_sid gsid; +- char *resstr; +- int ret; ++ struct dom_sid gsid, domsid; ++ char *resstr = NULL; ++ char *flat_domain_name = NULL; ++ char *flat_server_name = NULL; ++ char *fallback_group = NULL; ++ uint32_t fallback_rid; + time_t now; ++ const char *in_stmsg = NULL; ++ int err; ++ krb5_error_code trust_kerr = 0; ++ + + /* Do not update the mspac struct more than once a minute. This would + * avoid heavy load on the directory server if there are lots of requests + * from domains which we do not trust. */ + now = time(NULL); + +- if (ipactx->mspac != NULL && +- (force_reinit == false) && +- (now > ipactx->mspac->last_update) && +- (now - ipactx->mspac->last_update) < 60) { +- return 0; +- } +- +- if (ipactx->mspac && ipactx->mspac->num_trusts == 0) { +- /* Check if there is any trust configured. If not, just return +- * and do not re-initialize the MS-PAC structure. */ +- kerr = ipadb_mspac_check_trusted_domains(ipactx); +- if (kerr == KRB5_KDB_NOENTRY) { +- kerr = 0; +- goto done; +- } else if (kerr != 0) { +- goto done; ++ if (ipactx->mspac) { ++ if (!force_reinit && ++ (now > ipactx->mspac->last_update) && ++ (now - ipactx->mspac->last_update) < 60) { ++ /* SKIP */ ++ err = 0; ++ goto end; + } +- } +- +- /* clean up in case we had old values around */ +- ipadb_mspac_struct_free(&ipactx->mspac); + +- ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac)); +- if (!ipactx->mspac) { +- kerr = ENOMEM; +- goto done; ++ if (ipactx->mspac->num_trusts == 0) { ++ /* Check if there is any trust configured. If not, just return ++ * and do not re-initialize the MS-PAC structure. */ ++ err = ipadb_mspac_check_trusted_domains(ipactx); ++ if (err) { ++ if (err == KRB5_KDB_NOENTRY) { ++ /* SKIP */ ++ err = 0; ++ } else { ++ in_stmsg = "Failed to fetch trusted domains information"; ++ } ++ goto end; ++ } ++ } + } + +- ipactx->mspac->last_update = now; +- +- kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE, +- "(objectclass=ipaNTDomainAttrs)", dom_attrs, +- &result); +- if (kerr == KRB5_KDB_NOENTRY) { +- return ENOENT; +- } else if (kerr != 0) { +- return EIO; ++ err = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE, ++ "(objectclass=ipaNTDomainAttrs)", dom_attrs, ++ &result); ++ if (err == KRB5_KDB_NOENTRY) { ++ err = ENOENT; ++ in_stmsg = "Local domain NT attributes not configured"; ++ goto end; ++ } else if (err) { ++ err = EIO; ++ in_stmsg = "Failed to fetch local domain NT attributes"; ++ goto end; + } + + lentry = ldap_first_entry(ipactx->lcontext, result); + if (!lentry) { +- kerr = ENOENT; +- goto done; ++ err = ENOENT; ++ in_stmsg = "Local domain NT attributes not configured"; ++ goto end; + } + +- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, +- "ipaNTFlatName", +- &ipactx->mspac->flat_domain_name); +- if (ret) { +- kerr = ret; +- goto done; ++ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, "ipaNTFlatName", ++ &flat_domain_name); ++ if (err) { ++ in_stmsg = "Local domain NT flat name not configured"; ++ goto end; + } + +- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, +- "ipaNTSecurityIdentifier", +- &resstr); +- if (ret) { +- kerr = ret; +- goto done; ++ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, ++ "ipaNTSecurityIdentifier", &resstr); ++ if (err) { ++ in_stmsg = "Local domain SID not configured"; ++ goto end; + } + +- ret = ipadb_string_to_sid(resstr, &ipactx->mspac->domsid); +- if (ret) { +- kerr = ret; +- free(resstr); +- goto done; ++ err = ipadb_string_to_sid(resstr, &domsid); ++ if (err) { ++ in_stmsg = "Malformed local domain SID"; ++ goto end; + } ++ + free(resstr); + +- free(ipactx->mspac->flat_server_name); +- ipactx->mspac->flat_server_name = get_server_netbios_name(ipactx); +- if (!ipactx->mspac->flat_server_name) { +- kerr = ENOMEM; +- goto done; ++ flat_server_name = get_server_netbios_name(ipactx); ++ if (!flat_server_name) { ++ err = ENOMEM; ++ goto end; + } + +- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, +- "ipaNTFallbackPrimaryGroup", +- &ipactx->mspac->fallback_group); +- if (ret && ret != ENOENT) { +- kerr = ret; +- goto done; ++ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, ++ "ipaNTFallbackPrimaryGroup", &fallback_group); ++ if (err) { ++ in_stmsg = (err == ENOENT) ++ ? "Local fallback primary group not configured" ++ : "Failed to fetch local fallback primary group"; ++ goto end; + } + + /* result and lentry not valid any more from here on */ +@@ -3095,53 +3105,81 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_rein + result = NULL; + lentry = NULL; + +- if (ret != ENOENT) { +- kerr = ipadb_simple_search(ipactx, ipactx->mspac->fallback_group, +- LDAP_SCOPE_BASE, +- "(objectclass=posixGroup)", +- grp_attrs, &result); +- if (kerr && kerr != KRB5_KDB_NOENTRY) { +- kerr = ret; +- goto done; +- } ++ err = ipadb_simple_search(ipactx, fallback_group, LDAP_SCOPE_BASE, ++ "(objectclass=posixGroup)", grp_attrs, &result); ++ if (err) { ++ in_stmsg = (err == KRB5_KDB_NOENTRY) ++ ? "Local fallback primary group has no POSIX definition" ++ : "Failed to fetch SID of POSIX group mapped as local fallback " \ ++ "primary group"; ++ goto end; ++ } + +- lentry = ldap_first_entry(ipactx->lcontext, result); +- if (!lentry) { +- kerr = ENOENT; +- goto done; +- } ++ lentry = ldap_first_entry(ipactx->lcontext, result); ++ if (!lentry) { ++ err = ENOENT; ++ goto end; ++ } + +- if (kerr == 0) { +- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, +- "ipaNTSecurityIdentifier", +- &resstr); +- if (ret && ret != ENOENT) { +- kerr = ret; +- goto done; +- } +- if (ret == 0) { +- ret = ipadb_string_to_sid(resstr, &gsid); +- if (ret) { +- free(resstr); +- kerr = ret; +- goto done; +- } +- ret = sid_split_rid(&gsid, &ipactx->mspac->fallback_rid); +- if (ret) { +- free(resstr); +- kerr = ret; +- goto done; +- } +- free(resstr); +- } +- } ++ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, ++ "ipaNTSecurityIdentifier", &resstr); ++ if (err) { ++ in_stmsg = (err == ENOENT) ++ ? "The POSIX group set as fallback primary group has no SID " \ ++ "configured" ++ : "Failed to fetch SID of POSIX group set as local fallback " \ ++ "primary group"; ++ goto end; + } + +- kerr = ipadb_mspac_get_trusted_domains(ipactx); ++ err = ipadb_string_to_sid(resstr, &gsid); ++ if (err) { ++ in_stmsg = "Malformed SID of POSIX group set as local fallback " \ ++ "primary group"; ++ goto end; ++ } + +-done: ++ err = sid_split_rid(&gsid, &fallback_rid); ++ if (err) { ++ in_stmsg = "Malformed SID of POSIX group mapped as local fallback " \ ++ "primary group"; ++ goto end; ++ } ++ ++ /* clean up in case we had old values around */ ++ ipadb_mspac_struct_free(&ipactx->mspac); ++ ++ ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac)); ++ if (!ipactx->mspac) { ++ err = ENOMEM; ++ goto end; ++ } ++ ++ ipactx->mspac->last_update = now; ++ ipactx->mspac->flat_domain_name = flat_domain_name; ++ ipactx->mspac->flat_server_name = flat_server_name; ++ ipactx->mspac->domsid = domsid; ++ ipactx->mspac->fallback_group = fallback_group; ++ ipactx->mspac->fallback_rid = fallback_rid; ++ ++ trust_kerr = ipadb_mspac_get_trusted_domains(ipactx); ++ if (trust_kerr) ++ in_stmsg = "Failed to assemble trusted domains information"; ++ ++end: ++ if (stmsg) ++ *stmsg = in_stmsg; ++ ++ if (resstr) free(resstr); + ldap_msgfree(result); +- return kerr; ++ ++ if (err) { ++ if (flat_domain_name) free(flat_domain_name); ++ if (flat_server_name) free(flat_server_name); ++ if (fallback_group) free(fallback_group); ++ } ++ ++ return err ? (krb5_error_code)err : trust_kerr; + } + + krb5_error_code ipadb_check_transited_realms(krb5_context kcontext, +@@ -3151,11 +3189,11 @@ krb5_error_code ipadb_check_transited_realms(krb5_context kcontext, + { + struct ipadb_context *ipactx; + bool has_transited_contents, has_client_realm, has_server_realm; +- int i; ++ size_t i; + krb5_error_code ret; + + ipactx = ipadb_get_context(kcontext); +- if (!ipactx || !ipactx->mspac) { ++ if (!ipactx) { + return KRB5_KDB_DBNOTINITED; + } + +@@ -3217,7 +3255,7 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + char **trusted_realm) + { + struct ipadb_context *ipactx; +- int i, j, length; ++ size_t i, j, length; + const char *name; + bool result = false; + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_private.h b/daemons/ipa-kdb/ipa_kdb_mspac_private.h +index 7f0ca7a79..e650cfa73 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac_private.h ++++ b/daemons/ipa-kdb/ipa_kdb_mspac_private.h +@@ -31,7 +31,7 @@ struct ipadb_mspac { + char *fallback_group; + uint32_t fallback_rid; + +- int num_trusts; ++ size_t num_trusts; + struct ipadb_adtrusts *trusts; + time_t last_update; + }; +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c +index faf47ad1b..96cd50e4c 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c +@@ -233,6 +233,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, + krb5_db_entry *client_entry = NULL; + krb5_boolean is_equal; + bool force_reinit_mspac = false; ++ const char *stmsg = NULL; + + + is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); +@@ -309,7 +310,9 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, + force_reinit_mspac = true; + } + +- (void)ipadb_reinit_mspac(ipactx, force_reinit_mspac); ++ kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg); ++ if (kerr && stmsg) ++ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg); + + kerr = ipadb_get_pac(context, flags, client, server, NULL, authtime, &pac); + if (kerr != 0 && kerr != ENOENT) { +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_v9.c b/daemons/ipa-kdb/ipa_kdb_mspac_v9.c +index 3badd5b08..60db048e1 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac_v9.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac_v9.c +@@ -46,6 +46,7 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags, + bool with_pad; + krb5_error_code kerr = 0; + bool is_as_req = flags & CLIENT_REFERRALS_FLAGS; ++ const char *stmsg = NULL; + + if (is_as_req) { + get_authz_data_types(context, client, &with_pac, &with_pad); +@@ -110,12 +111,19 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags, + force_reinit_mspac = TRUE; + } + } +- (void)ipadb_reinit_mspac(ipactx, force_reinit_mspac); + +- /* MS-PAC needs proper configuration and if it is missing, we simply skip issuing one */ +- if (ipactx->mspac->flat_server_name == NULL) { ++ /* MS-PAC generator has to be initalized */ ++ kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg); ++ if (kerr && stmsg) ++ krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg); ++ ++ /* Continue even if initilization of PAC generator failed. ++ * It may caused by the trust objects part only. */ ++ ++ /* At least the core part of the PAC generator is required. */ ++ if (!ipactx->mspac) + return KRB5_PLUGIN_OP_NOTSUPP; +- } ++ + kerr = ipadb_get_pac(context, flags, + client, server, replaced_reply_key, + authtime, &new_pac); +diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c +index fadb132ed..07cc87746 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -1495,6 +1495,7 @@ static krb5_error_code dbget_alias(krb5_context kcontext, + krb5_db_entry *kentry = NULL; + krb5_data *realm; + krb5_boolean check = FALSE; ++ const char *stmsg = NULL; + + /* TODO: also support hostbased aliases */ + +@@ -1562,8 +1563,11 @@ static krb5_error_code dbget_alias(krb5_context kcontext, + if (kerr == KRB5_KDB_NOENTRY) { + /* If no trusted realm found, refresh trusted domain data and try again + * because it might be a freshly added trust to AD */ +- kerr = ipadb_reinit_mspac(ipactx, false); ++ kerr = ipadb_reinit_mspac(ipactx, false, &stmsg); + if (kerr != 0) { ++ if (stmsg) ++ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", ++ stmsg); + kerr = KRB5_KDB_NOENTRY; + goto done; + } +-- +2.43.0 + diff --git a/SOURCES/0018-ipatests-fix-tasks-wait_for_replication-method_rhel#25708.patch b/SOURCES/0018-ipatests-fix-tasks-wait_for_replication-method_rhel#25708.patch new file mode 100644 index 0000000..c433849 --- /dev/null +++ b/SOURCES/0018-ipatests-fix-tasks-wait_for_replication-method_rhel#25708.patch @@ -0,0 +1,34 @@ +From 44a762413c83f9637399afeb61b1e4b1ac111260 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Feb 14 2024 12:24:48 +0000 +Subject: ipatests: fix tasks.wait_for_replication method + + +With the fix for https://pagure.io/freeipa/issue/9171, the +method entry.single_value['nsds5replicaupdateinprogress'] now +returns a Boolean instead of a string "TRUE"/"FALSE". + +The method tasks.wait_for_replication needs to be fixed so that +it properly detects when replication is not done. + +Fixes: https://pagure.io/freeipa/issue/9530 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden + +--- + +diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py +index 9068ba6..952c9e6 100755 +--- a/ipatests/pytest_ipa/integration/tasks.py ++++ b/ipatests/pytest_ipa/integration/tasks.py +@@ -1510,7 +1510,7 @@ def wait_for_replication(ldap, timeout=30, + statuses = [entry.single_value[status_attr] for entry in entries] + wrong_statuses = [s for s in statuses + if not re.match(target_status_re, s)] +- if any(e.single_value[progress_attr] == 'TRUE' for e in entries): ++ if any(e.single_value[progress_attr] for e in entries): + msg = 'Replication not finished' + logger.debug(msg) + elif wrong_statuses: + diff --git a/SOURCES/0019-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch b/SOURCES/0019-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch new file mode 100644 index 0000000..1daf696 --- /dev/null +++ b/SOURCES/0019-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch @@ -0,0 +1,127 @@ +From 163f06cab678d517ab30ab6da59ae339f39ee7cf Mon Sep 17 00:00:00 2001 +From: Francisco Trivino +Date: Fri, 27 May 2022 17:31:40 +0200 +Subject: [PATCH] Vault: add support for RSA-OAEP wrapping algo + +None of the FIPS certified modules in RHEL support PKCS#1 v1.5 as FIPS +approved mechanism. This commit adds support for RSA-OAEP padding as a +fallback. + +Fixes: https://pagure.io/freeipa/issue/9191 + +Signed-off-by: Francisco Trivino +Reviewed-By: Rob Crittenden +(cherry picked from commit b1fb31fd20c900c9ff1d5d28dfe136439f6bf605) +--- + ipaclient/plugins/vault.py | 57 ++++++++++++++++++++++++++++++-------- + 1 file changed, 45 insertions(+), 12 deletions(-) + +diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py +index d4c84eb6b..ed16c73ae 100644 +--- a/ipaclient/plugins/vault.py ++++ b/ipaclient/plugins/vault.py +@@ -119,8 +119,8 @@ def encrypt(data, symmetric_key=None, public_key=None): + return public_key_obj.encrypt( + data, + padding.OAEP( +- mgf=padding.MGF1(algorithm=hashes.SHA1()), +- algorithm=hashes.SHA1(), ++ mgf=padding.MGF1(algorithm=hashes.SHA256()), ++ algorithm=hashes.SHA256(), + label=None + ) + ) +@@ -154,8 +154,8 @@ def decrypt(data, symmetric_key=None, private_key=None): + return private_key_obj.decrypt( + data, + padding.OAEP( +- mgf=padding.MGF1(algorithm=hashes.SHA1()), +- algorithm=hashes.SHA1(), ++ mgf=padding.MGF1(algorithm=hashes.SHA256()), ++ algorithm=hashes.SHA256(), + label=None + ) + ) +@@ -705,14 +705,39 @@ class ModVaultData(Local): + return transport_cert, wrapping_algo + + def _do_internal(self, algo, transport_cert, raise_unexpected, +- *args, **options): ++ use_oaep=False, *args, **options): + public_key = transport_cert.public_key() + + # wrap session key with transport certificate +- wrapped_session_key = public_key.encrypt( +- algo.key, +- padding.PKCS1v15() +- ) ++ # KRA may be configured using either the default PKCS1v15 or RSA-OAEP. ++ # there is no way to query this info using the REST interface. ++ if not use_oaep: ++ # PKCS1v15() causes an OpenSSL exception when FIPS is enabled ++ # if so, we fallback to RSA-OAEP ++ try: ++ wrapped_session_key = public_key.encrypt( ++ algo.key, ++ padding.PKCS1v15() ++ ) ++ except ValueError: ++ wrapped_session_key = public_key.encrypt( ++ algo.key, ++ padding.OAEP( ++ mgf=padding.MGF1(algorithm=hashes.SHA256()), ++ algorithm=hashes.SHA256(), ++ label=None ++ ) ++ ) ++ else: ++ wrapped_session_key = public_key.encrypt( ++ algo.key, ++ padding.OAEP( ++ mgf=padding.MGF1(algorithm=hashes.SHA256()), ++ algorithm=hashes.SHA256(), ++ label=None ++ ) ++ ) ++ + options['session_key'] = wrapped_session_key + + name = self.name + '_internal' +@@ -723,7 +748,7 @@ class ModVaultData(Local): + errors.ExecutionError, + errors.GenericError): + _kra_config_cache.remove(self.api.env.domain) +- if raise_unexpected: ++ if raise_unexpected and use_oaep: + raise + return None + +@@ -733,15 +758,23 @@ class ModVaultData(Local): + """ + # try call with cached transport certificate + result = self._do_internal(algo, transport_cert, False, +- *args, **options) ++ False, *args, **options) + if result is not None: + return result + + # retrieve transport certificate (cached by vaultconfig_show) + transport_cert = self._get_vaultconfig(force_refresh=True)[0] ++ + # call with the retrieved transport certificate ++ result = self._do_internal(algo, transport_cert, True, ++ False, *args, **options) ++ ++ if result is not None: ++ return result ++ ++ # call and use_oaep this time, last attempt + return self._do_internal(algo, transport_cert, True, +- *args, **options) ++ True, *args, **options) + + + @register(no_fail=True) +-- +2.43.0 + diff --git a/SOURCES/0020-Vault-improve-vault-server-archival-retrieval-calls-.patch b/SOURCES/0020-Vault-improve-vault-server-archival-retrieval-calls-.patch new file mode 100644 index 0000000..2fed594 --- /dev/null +++ b/SOURCES/0020-Vault-improve-vault-server-archival-retrieval-calls-.patch @@ -0,0 +1,88 @@ +From 84798137fabf75fe79aebbd97e4b8418de8ab0f2 Mon Sep 17 00:00:00 2001 +From: Francisco Trivino +Date: Fri, 19 Jan 2024 18:15:28 +0100 +Subject: [PATCH] Vault: improve vault server archival/retrieval calls + error handling + +If a vault operation fails, the error message just says "InternalError". This commit +improves error handling of key archival and retrieval calls by catching the PKIException +error and raising it as an IPA error. + +Related: https://pagure.io/freeipa/issue/9191 + +Signed-off-by: Francisco Trivino +Reviewed-By: Rob Crittenden +(cherry picked from commit dc1ab53f0aa0398d493f7440b5ec4d70d9c7d663) +--- + ipaserver/plugins/vault.py | 40 +++++++++++++++++++++++++------------- + 1 file changed, 26 insertions(+), 14 deletions(-) + +diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py +index 574c83a9a..13c4fac9a 100644 +--- a/ipaserver/plugins/vault.py ++++ b/ipaserver/plugins/vault.py +@@ -45,6 +45,7 @@ if api.env.in_server: + import pki.key + from pki.crypto import DES_EDE3_CBC_OID + from pki.crypto import AES_128_CBC_OID ++ from pki import PKIException + + if six.PY3: + unicode = str +@@ -1094,16 +1095,21 @@ class vault_archive_internal(PKQuery): + pki.key.KeyClient.KEY_STATUS_INACTIVE) + + # forward wrapped data to KRA +- kra_client.keys.archive_encrypted_data( +- client_key_id, +- pki.key.KeyClient.PASS_PHRASE_TYPE, +- wrapped_vault_data, +- wrapped_session_key, +- algorithm_oid=algorithm_oid, +- nonce_iv=nonce, +- ) +- +- kra_account.logout() ++ try: ++ kra_client.keys.archive_encrypted_data( ++ client_key_id, ++ pki.key.KeyClient.PASS_PHRASE_TYPE, ++ wrapped_vault_data, ++ wrapped_session_key, ++ algorithm_oid=algorithm_oid, ++ nonce_iv=nonce, ++ ) ++ except PKIException as e: ++ kra_account.logout() ++ raise errors.EncodingError( ++ message=_("Unable to archive key: %s") % e) ++ finally: ++ kra_account.logout() + + response = { + 'value': args[-1], +@@ -1174,11 +1180,17 @@ class vault_retrieve_internal(PKQuery): + kra_client.keys.encrypt_alg_oid = algorithm_oid + + # retrieve encrypted data from KRA +- key = kra_client.keys.retrieve_key( +- key_info.get_key_id(), +- wrapped_session_key) ++ try: + +- kra_account.logout() ++ key = kra_client.keys.retrieve_key( ++ key_info.get_key_id(), ++ wrapped_session_key) ++ except PKIException as e: ++ kra_account.logout() ++ raise errors.EncodingError( ++ message=_("Unable to retrieve key: %s") % e) ++ finally: ++ kra_account.logout() + + response = { + 'value': args[-1], +-- +2.43.0 + diff --git a/SOURCES/0021-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch b/SOURCES/0021-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch new file mode 100644 index 0000000..42cc639 --- /dev/null +++ b/SOURCES/0021-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch @@ -0,0 +1,98 @@ +From a406fd9aec7d053c044e73f16b05489bebd84bc8 Mon Sep 17 00:00:00 2001 +From: Francisco Trivino +Date: Fri, 19 Jan 2024 17:12:07 +0100 +Subject: [PATCH] kra: set RSA-OAEP as default wrapping algo when FIPS is + enabled + +Vault uses PKCS1v15 as default padding wrapping algo, which is not an approved +FIPS algorithm. This commit ensures that KRA is installed with RSA-OAEP if FIPS +is enabled. It also handles upgrade path. + +Fixes: https://pagure.io/freeipa/issue/9191 + +Signed-off-by: Francisco Trivino +Reviewed-By: Rob Crittenden +(cherry picked from commit f2eec9eb208e62f923375b9eaf34fcc491046a0d) +--- + install/share/ipaca_default.ini | 3 +++ + ipaserver/install/dogtaginstance.py | 4 +++- + ipaserver/install/krainstance.py | 12 ++++++++++++ + ipaserver/install/server/upgrade.py | 12 ++++++++++++ + 4 files changed, 30 insertions(+), 1 deletion(-) + +diff --git a/install/share/ipaca_default.ini b/install/share/ipaca_default.ini +index 082f507b2..691f1e1b7 100644 +--- a/install/share/ipaca_default.ini ++++ b/install/share/ipaca_default.ini +@@ -166,3 +166,6 @@ pki_audit_signing_subject_dn=cn=KRA Audit,%(ipa_subject_base)s + # We will use the dbuser created for the CA. + pki_share_db=True + pki_share_dbuser_dn=uid=pkidbuser,ou=people,o=ipaca ++ ++# KRA padding, set RSA-OAEP in FIPS mode ++pki_use_oaep_rsa_keywrap=%(fips_use_oaep_rsa_keywrap)s +\ No newline at end of file +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index c2c6b3f49..c3c726f68 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -1020,7 +1020,9 @@ class PKIIniLoader: + # for softhsm2 testing + softhsm2_so=paths.LIBSOFTHSM2_SO, + # Configure a more secure AJP password by default +- ipa_ajp_secret=ipautil.ipa_generate_password(special=None) ++ ipa_ajp_secret=ipautil.ipa_generate_password(special=None), ++ # in FIPS mode use RSA-OAEP wrapping padding algo as default ++ fips_use_oaep_rsa_keywrap=tasks.is_fips_enabled() + ) + + @classmethod +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index 13cb2dcaa..0e04840a1 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -277,6 +277,18 @@ class KRAInstance(DogtagInstance): + + # A restart is required + ++ def enable_oaep_wrap_algo(self): ++ """ ++ Enable KRA OAEP key wrap algorithm ++ """ ++ with installutils.stopped_service('pki-tomcatd', 'pki-tomcat'): ++ directivesetter.set_directive( ++ self.config, ++ 'keyWrap.useOAEP', ++ 'true', quotes=False, separator='=') ++ ++ # A restart is required ++ + def update_cert_config(self, nickname, cert): + """ + When renewing a KRA subsystem certificate the configuration file +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index e4dc7ae73..c84516b56 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1780,6 +1780,18 @@ def upgrade_configuration(): + else: + logger.info('ephemeralRequest is already enabled') + ++ if tasks.is_fips_enabled(): ++ logger.info('[Ensuring KRA OAEP wrap algo is enabled in FIPS]') ++ value = directivesetter.get_directive( ++ paths.KRA_CS_CFG_PATH, ++ 'keyWrap.useOAEP', ++ separator='=') ++ if value is None or value.lower() != 'true': ++ logger.info('Use the OAEP key wrap algo') ++ kra.enable_oaep_wrap_algo() ++ else: ++ logger.info('OAEP key wrap algo is already enabled') ++ + # several upgrade steps require running CA. If CA is configured, + # always run ca.start() because we need to wait until CA is really ready + # by checking status using http +-- +2.43.0 + diff --git a/SOURCES/0022-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch b/SOURCES/0022-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch new file mode 100644 index 0000000..5745101 --- /dev/null +++ b/SOURCES/0022-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch @@ -0,0 +1,29 @@ +From a8e433f7c8d844d9f337a34db09b0197f2dbc5af Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Tue, 20 Feb 2024 15:14:24 +0100 +Subject: [PATCH] ipa-kdb: Fix double free in ipadb_reinit_mspac() + +Fixes: https://pagure.io/freeipa/issue/9535 + +Signed-off-by: Julien Rische +Reviewed-By: Florence Blanc-Renaud +(cherry picked from commit dd27d225524aa81c038a970961a4f878cf742e2a) +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index deed513b9..0964d112a 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3084,6 +3084,7 @@ ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit, + } + + free(resstr); ++ resstr = NULL; + + flat_server_name = get_server_netbios_name(ipactx); + if (!flat_server_name) { +-- +2.43.0 + diff --git a/SOURCES/freeipa-4.9.12.tar.gz.asc b/SOURCES/freeipa-4.9.12.tar.gz.asc deleted file mode 100644 index 699aa14..0000000 --- a/SOURCES/freeipa-4.9.12.tar.gz.asc +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmRnL+gACgkQaYdvcqbi -00/1Gg/8CFABojXZyUkQnWeaHdrFeHeE+DW2qTs9Wr/TQwF67fYkh7lj3p+WqMlD -kMMNAfLn4wUnJNDMv64QlE6RAz71KetQlQt+mZQVT9M0nDepLhBw86qmNbJj611J -+2B79hzNLT8tmOf9NyLRJbFp3QebSPELX9hycPj1Ovd1tr/61tcwcNzE6ZLrX5vb -IPkCT2bo+6MceIsR50tTRxxK6J9jFYX73PjHJ5Ix7ssDf4vg2OBRTwUdLeZAkWlA -q+0bPPp+F3PWLhnSs+vIs5plHUI/hcGCt9pTvw/d6jUUxuwZadGGbRZSyDN7aj2Q -zEXeZsCtOSk5cx65lWHl+7TTyVvCoemeZPZ92EiCtVJfiuK3/6a/WFWanBZoO0E3 -N0p6HUcvIRPrEj0nQwH2vr0zkfSPA4g30k+Q9qeP3ArN+i+5OFfuiwiqk1AIJ2rv -ERhBRryOaNeiVpYghMQdtacWP/qQunfH6VdhA61Q089/lhomGeSytQI+fV4TXOhV -ldV7dftaWpQT3QYWSsKzoiHpyjIwOA8dBvQF2YDX7LNmeO/hj4ToFp00CVCWdb0j -MHs2X9p42kkhw2oZOf3GNyNvpybxUv59ER4YDEHbj8+iZyVjiqfcp71373DqpieW -iGjB3Wc0gO3cdYk3Mdl0SgkD7k0U9iwwh7qJeqqUYT3gKf9mqbY= -=dT0o ------END PGP SIGNATURE----- diff --git a/SOURCES/freeipa-4.9.13.tar.gz.asc b/SOURCES/freeipa-4.9.13.tar.gz.asc new file mode 100644 index 0000000..cdb062f --- /dev/null +++ b/SOURCES/freeipa-4.9.13.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmVbZU0ACgkQaYdvcqbi +009Fgw/+PzHGNOJPs67TtoYITV/3ZCzMyrYTcazVACjD61Zw7JBgbZzZpQXxBSbj +7QWpNJa3P2JFtv2qOUXJto40mOGpMynyYpuYs4CtyJ86eHTUJyYTFppBmCzzozhT +2C2BeKKjzV8OOWQ7yO/2BTEZ7KtOcIr4ZI7iZCnLJF9Yt8x7TURjGRqxsHwT62Ip +vcrtm0LkkYv/fQ6pFZZfinKU1OBrZphwHMCU4Mlv411iQg4+NOxLSsVU/kegeKIO +adp4Y9g5dfAfdXEXb2Zt7gkmLaWMgf+XNSFDL/wkzRYt74HKwvbIPJQlTZ6pqLxQ +yTtiHGuMb7xNDWolpoueo1/lbxaHRRGJaSPs7zUht3IBxb7hiF65Gm3UaJhoeAXc +gVleZf/+0titOdkRfTD2N0P0hli7gaiRrbpw8K4joxMFpYrQGUxD8SI376gkOj6o +5RWSioPoG9txNM7Co+lVpci7WHhL+Tmhf1SlHyVJGKoNe/z4VHnjHeYlFWRVdDEI +OOupZzJQoLnso3lTwR5VEN8xGURnhbGV4MdUfD/6FhwmyHiPlYkytdZIsGsNDOab +978PPaKcIpbsZ4gUhshcbn7qaY809lNSpMtg8saYOP4J/5Nu+i9X5bJqOmoX0rKa +gAJDY5har+lExRnTEdYEGVB8qen5lqi8r1oYjnDpkSpq6BRoAHA= +=uQom +-----END PGP SIGNATURE----- diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec index 4db2e66..ce97973 100644 --- a/SPECS/ipa.spec +++ b/SPECS/ipa.spec @@ -64,7 +64,7 @@ %if 0%{?rhel} %global package_name ipa %global alt_name freeipa -%global krb5_version 1.18.2-25 +%global krb5_version 1.18.2-26 %global krb5_kdb_version 8.0 # 0.7.16: https://github.com/drkjam/netaddr/issues/71 %global python_netaddr_version 0.7.19 @@ -176,7 +176,7 @@ # Work-around fact that RPM SPEC parser does not accept # "Version: @VERSION@" in freeipa.spec.in used for Autoconf string replacement -%define IPA_VERSION 4.9.12 +%define IPA_VERSION 4.9.13 # Release candidate version -- uncomment with one percent for RC versions #%%global rc_version %%nil %define AT_SIGN @ @@ -189,7 +189,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 8%{?rc_version:.%rc_version}%{?dist} +Release: 7%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPLv3+ @@ -208,20 +208,29 @@ Source1: https://releases.pagure.org/freeipa/freeipa-%{version}%{?rc_vers # RHEL spec file only: START %if %{NON_DEVELOPER_BUILD} +Patch0001: 0001-Handle-samba-exception-type-change_rhel#17623.patch +Patch0002: 0002-Check-the-HTTP-Referer-header-on-all-requests.patch +Patch0003: 0003-Integration-tests-for-verifying-Referer-header-in-th.patch +Patch0004: 0004-ipa-kdb-Detect-and-block-Bronze-Bit-attacks.patch +Patch0005: 0005-Improve-server-affinity-for-ca-less-deployments_rhel#22283.patch +Patch0006: 0006-host-update-System-Manage-Host-Keytab-permission_rhel#22286.patch +Patch0007: 0007-adtrustinstance-make-sure-NetBIOS-name-defaults-are-set-properly_rhel#21938.patch +Patch0008: 0008-ipatests-Fix-healthcheck-report-when-nsslapd-accesslog-logbuffering-is-set-to-off_rhel#19672.patch +Patch0009: 0009-kdb-PAC-generator-do-not-fail-if-canonical-principal-is-missing_rhel#23630.patch +Patch0010: 0010-ipa-kdb-Fix-memory-leak-during-PAC-verification_rhel#22644.patch +Patch0011: 0011-Fix-session-cookie-access_rhel#23622.patch +Patch0012: 0012-Do-not-ignore-staged-users-in-sidgen-plugin_rhel#23626.patch +Patch0013: 0013-ipa-kdb-Disable-Bronze-Bit-check-if-PAC-not-available_rhel#22313.patch +Patch0014: 0014-krb5kdc-Fix-start-when-pkinit-and-otp-auth-type-are-enabled_rhel#4874.patch +Patch0015: 0015-hbactest-was-not-collecting-or-returning-messages_rhel#12780.patch +Patch0016: 0016-ipatests-wait-for-replica-update-in-test_dns_locatio.patch +Patch0017: 0017-ipa-kdb-Rework-ipadb_reinit_mspac.patch +Patch0018: 0018-ipatests-fix-tasks-wait_for_replication-method_rhel#25708.patch +Patch0019: 0019-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch +Patch0020: 0020-Vault-improve-vault-server-archival-retrieval-calls-.patch +Patch0021: 0021-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch +Patch0022: 0022-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch %if 0%{?rhel} >= 8 -Patch0001: 0001-user-or-group-name-explain-the-supported-format_rhbz#2150217.patch -Patch0002: 0002-Use-the-python-cryptography-parser-directly-in-cert-find_rhbz#2164349.patch -Patch0003: 0003-Upgrade-add-PKI-drop-in-file-if-missing_rhbz#2215336.patch -Patch0004: 0004-Upgrade-fix-replica-agreement_rhbz#2216551.patch -Patch0005: 0005-OTP-fix-data-type-to-avoid-endianness-issue_rhbz#2218293.patch -Patch0006: 0006-Backport-test-updates-8-9-release_rhbz#2218847.patch -Patch0007: 0007-ipa-kdb-fix-error-handling-of-is_master_host_rhbz#2214638.patch -Patch0008: 0008-ipatests-enable-firewall-rule-for-http-service-on-acme-client_rhbz#2230256.patch -Patch0009: 0009-User-plugin-improve-error-related-to-non-existing-idp_rhbz#2224572.patch -Patch0010: 0010-Prevent-admin-user-from-being-deleted_rhbz#1921181.patch -Patch0011: 0011-Fix-memory-leak-in-the-OTP-last-token-plugin_rhbz#2227783.patch -Patch0012: 0012-ipatests-fix-test_topology_rhbz#2232351.patch -Patch0013: 0013-Installer-activate-nss-and-pam-services-in-sssd.conf_rhbz#2216532.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch Patch1003: 1003-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch @@ -1736,6 +1745,69 @@ fi %endif %changelog +* Tue Feb 20 2024 Julien Rische - 4.9.13-7 +- ipa-kdb: Fix double free in ipadb_reinit_mspac() + Resolves: RHEL-25742 +- kra: set RSA-OAEP as default wrapping algo when FIPS is enabled + Resolves: RHEL-12153 +- Vault: improve vault server archival/retrieval calls error handling + Resolves: RHEL-12153 +- Vault: add support for RSA-OAEP wrapping algo + Resolves: RHEL-12153 + +* Fri Feb 16 2024 Julien Rische - 4.9.13-6 +- ipa-kdb: Rework ipadb_reinit_mspac() + Resolves: RHEL-25742 +- ipatests: wait for replica update in test_dns_locations + Resolves: RHEL-22373 +- ipatests: fix tasks.wait_for_replication() method + Resolves: RHEL-25708 + +* Tue Feb 13 2024 Rafael Jeffman - 4.9.13-5 +- kdb: PAC generator: do not fail if canonical principal is missing + Resolves: RHEL-23630 +- ipa-kdb: Fix memory leak during PAC verification + Resolves: RHEL-22644 +- Fix session cookie access + Resolves: RHEL-23622 +- Do not ignore staged users in sidgen plugin + Resovlves: RHEL-23626 +- ipa-kdb: Disable Bronze-Bit check if PAC not available + Resolves: RHEL-22313 +- krb5kdc: Fix start when pkinit and otp auth type are enabled + Resolves: RHEL-4874 +- hbactest was not collecting or returning messages + Resolves: RHEL-12780 + + +* Tue Jan 23 2024 Rafael Jeffman - 4.9.13-4 +- Improve server affinity for CA-less deployments + Resolves: RHEL-22283 +- host: update system: Manage Host Keytab permission + Resolves: RHEL-22286 +- adtrustinstance: make sure NetBIOS name defaults are set properly + Resolves: RHEL-21938 +- ipatests: Fix healthcheck report when nsslapd accesslog logbuffering is set to off + Resolves: RHEL-19672 + +* Wed Jan 10 2024 Julien Rische - 4.9.13-3 +- ipa-kdb: Detect and block Bronze-Bit attacks + Resolves: RHEL-9984 +- Fix for CVE-2023-5455 + Resolves: RHEL-12578 + +* Thu Nov 30 2023 Rafael Jeffman - 4.9.13-2 +- Handle new samba exception types. + Resolves: RHEL-17623 + +* Tue Nov 21 2023 Rafael Jeffman - 4.9.13-1 +- Rebase ipa to 4.9.13 + Resolves: RHEL-16936 + +* Wed Oct 04 2023 Julien Rische - 4.9.12-9 +- ipa-kdb: Make AD-SIGNEDPATH optional with krb5 DAL 8 and older + Resolves: RHEL-12198 + * Thu Aug 31 2023 Rafael Jeffman - 4.9.12-8 - Require krb5 release 1.18.2-25 or later Resolves: RHBZ#2234711