diff --git a/.gitignore b/.gitignore index e26cdcd..5953ea6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/freeipa-4.10.2.tar.gz +SOURCES/freeipa-4.11.0.tar.gz diff --git a/.ipa.metadata b/.ipa.metadata index 51a266d..e3dd0c8 100644 --- a/.ipa.metadata +++ b/.ipa.metadata @@ -1 +1 @@ -17d580b7dccb1586898aa46c7ecdd2bd2754ee5f SOURCES/freeipa-4.10.2.tar.gz +991d8a605a9547e1dbdbbdf283f6eb20f759de4d SOURCES/freeipa-4.11.0.tar.gz diff --git a/SOURCES/0001-ipatests-fix-healthcheck-test-without-DNS.patch b/SOURCES/0001-ipatests-fix-healthcheck-test-without-DNS.patch new file mode 100644 index 0000000..730cc64 --- /dev/null +++ b/SOURCES/0001-ipatests-fix-healthcheck-test-without-DNS.patch @@ -0,0 +1,44 @@ +From 4c8512168f6a9f224277a4db055f5432af37a552 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 28 Sep 2023 17:39:32 +0200 +Subject: [PATCH] ipatests: fix healthcheck test without DNS + +ipa-healthcheck has added a new check for ipa-ca record +missing. The test needs to be adapted to handle the new check. + +Fixes: https://pagure.io/freeipa/issue/9459 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_ipahealthcheck.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 6e01642f36a3d39ac7b3c2721664b21356bf424b..822f550d2ee241a9dd14c99d75199e6207b78e9c 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -1640,13 +1640,19 @@ class TestIpaHealthCheckWithoutDNS(IntegrationTest): + "Got {count} ipa-ca AAAA records, expected {expected}", + "Expected URI record missing", + } +- else: ++ elif (parse_version(version) < parse_version('0.13')): + expected_msgs = { + "Expected SRV record missing", + "Unexpected ipa-ca address {ipaddr}", + "expected ipa-ca to contain {ipaddr} for {server}", + "Expected URI record missing", + } ++ else: ++ expected_msgs = { ++ "Expected SRV record missing", ++ "Expected URI record missing", ++ "missing IP address for ipa-ca server {server}", ++ } + + tasks.install_packages(self.master, HEALTHCHECK_PKG) + returncode, data = run_healthcheck( +-- +2.41.0 + diff --git a/SOURCES/0001-webuitests-close-notification-which-hides-Add-button.patch b/SOURCES/0001-webuitests-close-notification-which-hides-Add-button.patch deleted file mode 100644 index f554010..0000000 --- a/SOURCES/0001-webuitests-close-notification-which-hides-Add-button.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 4f6ebb5fdf6d2514d4683247e5d1bfc6022a500e 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 f1d9a9d624bc587634e03a86050627a648feb26d..e2976d73acd1f574f1164828be9d8e871b737d7f 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/0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch b/SOURCES/0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch deleted file mode 100644 index 34d91f6..0000000 --- a/SOURCES/0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 8d34f453fb139c4cef055a4963f307a760316a73 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 014b0f6ab34dd92c00c0187c2c86b8bfbaa70e81..56e1593bfcfa3eb7f9918fc6f2993d836884ea38 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 - diff --git a/SOURCES/0002-ipatests-fix-healthcheck-test-for-indent-option.patch b/SOURCES/0002-ipatests-fix-healthcheck-test-for-indent-option.patch new file mode 100644 index 0000000..174bc62 --- /dev/null +++ b/SOURCES/0002-ipatests-fix-healthcheck-test-for-indent-option.patch @@ -0,0 +1,47 @@ +From ca4ac6c06dd37deab5ba7c4df8789acf9e45d03e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 28 Sep 2023 12:48:37 +0200 +Subject: [PATCH] ipatests: fix healthcheck test for --indent option + +ipa-healthcheck --indent option expects an integer. The error +message changed with ipa-healthcheck 0.13. +Recent versions also check that the value is in the range 0-32. + +The test must be compatible with old and new versions. + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_ipahealthcheck.py | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 822f550d2ee241a9dd14c99d75199e6207b78e9c..35fcfe10508589ded021207a4eba4fb0143495b4 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -2412,12 +2412,19 @@ class TestIpaHealthCLI(IntegrationTest): + cmd = self.base_cmd + ["--indent", option] + result = self.master.run_command(cmd, raiseonerr=False) + assert result.returncode == 2 +- assert 'invalid int value' in result.stderr_text ++ assert ('invalid int value' in result.stderr_text ++ or 'is not an integer' in result.stderr_text) + +- # unusual success, arguably odd but not invalid :-) ++ version = tasks.get_healthcheck_version(self.master) + for option in ('-1', '5000'): + cmd = self.base_cmd + ["--indent", option] +- result = self.master.run_command(cmd) ++ result = self.master.run_command(cmd, raiseonerr=False) ++ if parse_version(version) >= parse_version('0.13'): ++ assert result.returncode == 2 ++ assert 'is not in the range 0-32' in result.stderr_text ++ else: ++ # Older versions did not check for a given allowed range ++ assert result.returncode == 0 + + def test_severity(self): + """ +-- +2.41.0 + diff --git a/SOURCES/0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch b/SOURCES/0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch deleted file mode 100644 index 9f55246..0000000 --- a/SOURCES/0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 276138087158c6b2ea76b43c754084144e543c0b Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Wed, 7 Jun 2023 11:32:21 -0400 -Subject: [PATCH] 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 ---- - freeipa.spec.in | 2 -- - ipaserver/plugins/cert.py | 26 +++----------------------- - 2 files changed, 3 insertions(+), 25 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 3e23bbfe9d054a3a9febf468de0bcb4a6e81bb32..bec9780a82fe0d9bc5a50a93bdce8aa7e27a9f30 100755 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -412,7 +412,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 -@@ -884,7 +883,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 400b1b3cec0aba82e699a4a981516e121f3e0c77..2e32f4ecd50ac92c28bcaffcebe9c2c87557858a 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, SerialNumber - from ipalib import api -@@ -1618,19 +1617,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() -@@ -1750,11 +1737,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 = [] -@@ -1813,14 +1795,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. --- -2.41.0 - diff --git a/SOURCES/0003-ipatests-fix-test_ipactl_scenario_check.patch b/SOURCES/0003-ipatests-fix-test_ipactl_scenario_check.patch new file mode 100644 index 0000000..c6ac0b8 --- /dev/null +++ b/SOURCES/0003-ipatests-fix-test_ipactl_scenario_check.patch @@ -0,0 +1,35 @@ +From 8ffcce91c694d83f6698a0539b970f41ea056e2d Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 21 Sep 2023 10:32:41 +0200 +Subject: [PATCH] ipatests: fix test_ipactl_scenario_check + +The test is comparing the PID of services before and after +calling ipactl start, expecting to have the same value. +It should not compare the pid for ipa-dnskeysyncd as this service +is automatically restarted upon failure. + +Fixes: https://pagure.io/freeipa/issue/9415 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_installation.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py +index 39fbff2b674296b0696defa7bac3efe35c89e0b7..68a442a9cd7746eec728ee38fda34dbc5361c59b 100644 +--- a/ipatests/test_integration/test_installation.py ++++ b/ipatests/test_integration/test_installation.py +@@ -695,7 +695,7 @@ def get_pki_tomcatd_pid(host): + def get_ipa_services_pids(host): + ipa_services_name = [ + "krb5kdc", "kadmin", "named", "httpd", "ipa-custodia", +- "pki_tomcatd", "ipa-dnskeysyncd" ++ "pki_tomcatd" + ] + pids_of_ipa_services = {} + for name in ipa_services_name: +-- +2.41.0 + diff --git a/SOURCES/0004-Revert-cert_find-fix-call-with-all.patch b/SOURCES/0004-Revert-cert_find-fix-call-with-all.patch deleted file mode 100644 index baaa558..0000000 --- a/SOURCES/0004-Revert-cert_find-fix-call-with-all.patch +++ /dev/null @@ -1,32 +0,0 @@ -From d83a4b0babdc7beb124d3748b5815ce309739eb7 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Tue, 13 Jun 2023 17:01:49 -0400 -Subject: [PATCH] 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 ---- - ipaserver/plugins/cert.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 2e32f4ecd50ac92c28bcaffcebe9c2c87557858a..36a0e8cb31b4dbdd9bff09165d1d8aa203936d37 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1807,7 +1807,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)) --- -2.41.0 - diff --git a/SOURCES/0004-ipalib-fix-the-IPACertificate-validity-dates.patch b/SOURCES/0004-ipalib-fix-the-IPACertificate-validity-dates.patch new file mode 100644 index 0000000..6b04dab --- /dev/null +++ b/SOURCES/0004-ipalib-fix-the-IPACertificate-validity-dates.patch @@ -0,0 +1,88 @@ +From d9ad56155e76f97ad9326d5c1bcc6e19eea3a0da Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 9 Oct 2023 13:54:17 +0200 +Subject: [PATCH] ipalib: fix the IPACertificate validity dates + +The class IPACertificate builds objects from x509 Certificate +objects and creates the not_valid_before and not_valid_after values +by converting to a timestamp + applying timezone delta to UTC + reading +from the timestamp. This results in applying twice the delta. + +Use a simpler method that replaces the timezone info with UTC in the +datetime object. + +Fixes: https://pagure.io/freeipa/issue/9462 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipalib/x509.py | 6 ++---- + ipatests/test_ipalib/test_x509.py | 25 +++++++++++++++++++++++++ + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/ipalib/x509.py b/ipalib/x509.py +index 7396688ae60cff76069c7325bab69441babfb8a7..769d480077e0d167646424627f252c336336f531 100644 +--- a/ipalib/x509.py ++++ b/ipalib/x509.py +@@ -266,13 +266,11 @@ class IPACertificate(crypto_x509.Certificate): + + @property + def not_valid_before(self): +- return datetime.datetime.fromtimestamp( +- self._cert.not_valid_before.timestamp(), tz=datetime.timezone.utc) ++ return self._cert.not_valid_before.replace(tzinfo=datetime.timezone.utc) + + @property + def not_valid_after(self): +- return datetime.datetime.fromtimestamp( +- self._cert.not_valid_after.timestamp(), tz=datetime.timezone.utc) ++ return self._cert.not_valid_after.replace(tzinfo=datetime.timezone.utc) + + @property + def tbs_certificate_bytes(self): +diff --git a/ipatests/test_ipalib/test_x509.py b/ipatests/test_ipalib/test_x509.py +index c25e8a0b5b6b918e50b155890fe20cfdd4d747c4..74287c84a581a800fa1c2700ad749fcacbc9d249 100644 +--- a/ipatests/test_ipalib/test_x509.py ++++ b/ipatests/test_ipalib/test_x509.py +@@ -26,6 +26,7 @@ from binascii import hexlify + from configparser import RawConfigParser + import datetime + from io import StringIO ++import os + import pickle + + import pytest +@@ -253,6 +254,30 @@ class test_x509: + b'+\x06\x01\x05\x05\x07\x03\x01' + ) + ++ def test_cert_with_timezone(self): ++ """ ++ Test the not_before and not_after values in a diffent timezone ++ ++ Test for https://pagure.io/freeipa/issue/9462 ++ """ ++ # Store initial timezone, then set to New York ++ tz = os.environ.get('TZ', None) ++ os.environ['TZ'] = 'America/New_York' ++ # Load the cert, extract not before and not after ++ cert = x509.load_pem_x509_certificate(goodcert_headers) ++ not_before = datetime.datetime(2010, 6, 25, 13, 0, 42, 0, ++ datetime.timezone.utc) ++ not_after = datetime.datetime(2015, 6, 25, 13, 0, 42, 0, ++ datetime.timezone.utc) ++ # Reset timezone to previous value ++ if tz: ++ os.environ['TZ'] = tz ++ else: ++ del os.environ['TZ'] ++ # ensure the timezone doesn't mess with not_before and not_after ++ assert cert.not_valid_before == not_before ++ assert cert.not_valid_after == not_after ++ + def test_load_pkcs7_pem(self): + certlist = x509.pkcs7_to_certs(good_pkcs7, datatype=x509.PEM) + assert len(certlist) == 1 +-- +2.41.0 + diff --git a/SOURCES/0005-Allow-password-policy-minlength-to-be-removed-like-o.patch b/SOURCES/0005-Allow-password-policy-minlength-to-be-removed-like-o.patch new file mode 100644 index 0000000..af3c80d --- /dev/null +++ b/SOURCES/0005-Allow-password-policy-minlength-to-be-removed-like-o.patch @@ -0,0 +1,135 @@ +From 9b0b723a0e62f18d41be53900ab8a3e710708563 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 18 May 2023 09:23:32 -0400 +Subject: [PATCH] Allow password policy minlength to be removed like other + values + +This is a side-effect of adding the libpwquality options. It +imposes its own hardcoded minimum password length so some care +was needed to ensure that it isn't set too low. + +So if there are no libpwquality options used then it's fine to +have no minlength in the policy. + +Fixes: https://pagure.io/freeipa/issue/9297 + +Signed-off-by: Rob Crittenden +Reviewed-By: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/plugins/pwpolicy.py | 10 +++-- + ipatests/test_integration/test_pwpolicy.py | 45 +++++++++++++++++++++- + 2 files changed, 50 insertions(+), 5 deletions(-) + +diff --git a/ipaserver/plugins/pwpolicy.py b/ipaserver/plugins/pwpolicy.py +index 5ea3e6b78c9ee98d204b8382fbed9e21edf51d10..15cfef45b69743c852e43d58b7428976b9e55681 100644 +--- a/ipaserver/plugins/pwpolicy.py ++++ b/ipaserver/plugins/pwpolicy.py +@@ -462,6 +462,7 @@ class pwpolicy(LDAPObject): + return False + + has_pwquality_value = False ++ min_length = 0 + if not add: + if len(keys) > 0: + existing_entry = self.api.Command.pwpolicy_show( +@@ -470,14 +471,15 @@ class pwpolicy(LDAPObject): + existing_entry = self.api.Command.pwpolicy_show( + all=True,)['result'] + existing_entry.update(entry_attrs) +- min_length = int(get_val(existing_entry, 'krbpwdminlength')) +- ++ if existing_entry.get('krbpwdminlength'): ++ min_length = int(get_val(existing_entry, 'krbpwdminlength')) + has_pwquality_value = has_pwquality_set(existing_entry) + else: +- min_length = int(get_val(entry_attrs, 'krbpwdminlength')) ++ if entry_attrs.get('krbpwdminlength'): ++ min_length = int(get_val(entry_attrs, 'krbpwdminlength')) + has_pwquality_value = has_pwquality_set(entry_attrs) + +- if min_length and min_length < 6 and has_pwquality_value: ++ if min_length < 6 and has_pwquality_value: + raise errors.ValidationError( + name='minlength', + error=_('Minimum length must be >= 6 if maxrepeat, ' +diff --git a/ipatests/test_integration/test_pwpolicy.py b/ipatests/test_integration/test_pwpolicy.py +index 41d6e9070a90c2bde7b3182ad6ecf1a923bba203..652c95e47bdab8bbe137f660d0b2ea2c0496c53e 100644 +--- a/ipatests/test_integration/test_pwpolicy.py ++++ b/ipatests/test_integration/test_pwpolicy.py +@@ -36,7 +36,9 @@ class TestPWPolicy(IntegrationTest): + cls.master.run_command(['ipa', 'group-add-member', POLICY, + '--users', USER]) + cls.master.run_command(['ipa', 'pwpolicy-add', POLICY, +- '--priority', '1', '--gracelimit', '-1']) ++ '--priority', '1', ++ '--gracelimit', '-1', ++ '--minlength', '6']) + cls.master.run_command(['ipa', 'passwd', USER], + stdin_text='{password}\n{password}\n'.format( + password=PASSWORD +@@ -92,6 +94,12 @@ class TestPWPolicy(IntegrationTest): + "--minlength", "0", + "--minclasses", "0",], + ) ++ # minlength => 6 is required for any of the libpwquality settings ++ self.master.run_command( ++ ["ipa", "pwpolicy-mod", POLICY, ++ "--minlength", "6"], ++ raiseonerr=False, ++ ) + + @pytest.fixture + def reset_pwpolicy(self): +@@ -212,6 +220,7 @@ class TestPWPolicy(IntegrationTest): + assert 'Password is too simple' in \ + result.stdout_text + ++ self.reset_password(self.master) + # test with valid password + for valid in ('Passw0rd', 'password1!', 'Password!'): + self.kinit_as_user(self.master, PASSWORD, valid) +@@ -252,6 +261,40 @@ class TestPWPolicy(IntegrationTest): + assert result.returncode != 0 + assert 'minlength' in result.stderr_text + ++ def test_minlength_empty(self, reset_pwpolicy): ++ """Test that the pwpolicy minlength can be blank ++ """ ++ # Ensure it is set to a non-zero value to avoid EmptyModlist ++ self.master.run_command( ++ ["ipa", "pwpolicy-mod", POLICY, ++ "--minlength", "10",] ++ ) ++ # Enable one of the libpwquality options, removing minlength ++ # should fail. ++ self.master.run_command( ++ ["ipa", "pwpolicy-mod", POLICY, ++ "--maxrepeat", "4",] ++ ) ++ result = self.master.run_command( ++ ["ipa", "pwpolicy-mod", POLICY, ++ "--minlength", "",], raiseonerr=False ++ ) ++ assert result.returncode != 0 ++ ++ # Remove the blocking value ++ self.master.run_command( ++ ["ipa", "pwpolicy-mod", POLICY, ++ "--maxrepeat", "",] ++ ) ++ ++ # Now erase it ++ result = self.master.run_command( ++ ["ipa", "pwpolicy-mod", POLICY, ++ "--minlength", "",] ++ ) ++ assert result.returncode == 0 ++ assert 'minlength' not in result.stderr_text ++ + def test_minlength_add(self): + """Test that adding a new policy with minlength is caught. + """ +-- +2.41.0 + diff --git a/SOURCES/0005-Use-the-python-cryptography-parser-directly-in-cert-.patch b/SOURCES/0005-Use-the-python-cryptography-parser-directly-in-cert-.patch deleted file mode 100644 index 1293cd0..0000000 --- a/SOURCES/0005-Use-the-python-cryptography-parser-directly-in-cert-.patch +++ /dev/null @@ -1,115 +0,0 @@ -From d9aa75459d650e5282a160a3eef09ed175dc5b51 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Wed, 7 Jun 2023 11:44:05 -0400 -Subject: [PATCH] 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 ---- - ipaserver/plugins/cert.py | 3 ++- - ipatests/test_xmlrpc/test_cert_plugin.py | 12 +++++++++++- - 2 files changed, 13 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 36a0e8cb31b4dbdd9bff09165d1d8aa203936d37..4fb85069a835d94969c9d05789714345ecc60e2e 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1795,7 +1795,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 433cebcd79f792e5c97307c6d599e50855ff4151..583c67fd942a61f42e578cc51a0e456cacf9a5e5 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. - --- -2.41.0 - diff --git a/SOURCES/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch b/SOURCES/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch deleted file mode 100644 index 407363f..0000000 --- a/SOURCES/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch +++ /dev/null @@ -1,38 +0,0 @@ -From f25003a730c0e28c22fae5fce607df734b55525c Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 19 Jun 2023 19:01:25 +0200 -Subject: [PATCH] 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 ---- - ipaserver/install/server/upgrade.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index f8701c8a0d43c7c1c1090e8576976b1c370b0104..8f3d57353605f28103c69cb0a34bf1c16fc4ae19 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1742,6 +1742,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: --- -2.41.0 - diff --git a/SOURCES/0006-ipatests-Skip-the-test-failing-due-to-FIPS-policy.patch b/SOURCES/0006-ipatests-Skip-the-test-failing-due-to-FIPS-policy.patch new file mode 100644 index 0000000..5d809a2 --- /dev/null +++ b/SOURCES/0006-ipatests-Skip-the-test-failing-due-to-FIPS-policy.patch @@ -0,0 +1,70 @@ +From cfb8748b23e93f84c2a6b03cc55d1116d7d1332e Mon Sep 17 00:00:00 2001 +From: Sudhir Menon +Date: Tue, 10 Oct 2023 15:22:27 +0530 +Subject: [PATCH] ipatests: Skip the test failing due to FIPS policy + +1. test_certmonger_reads_token_HSM test in test_installaton.py +is failing in FIPS/STIG mode with the below error. + +SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY: Unable to import. +Error attempting to import private key in STIG mode + +2. Adding the posfix config change, because there was a crash +seen in smtpd in FIPS mode. + +ie. postconf -e smtpd_tls_fingerprint_digest=sha256 + +KCS: https://access.redhat.com/solutions/6958957 + +Signed-off-by: Sudhir Menon +Reviewed-By: Florence Blanc-Renaud +--- + ipatests/test_integration/test_epn.py | 4 +++- + ipatests/test_integration/test_installation.py | 2 ++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/ipatests/test_integration/test_epn.py b/ipatests/test_integration/test_epn.py +index 8ea79cefbdd067b148ef0b7050c9fc803339371a..b391e32219bb0a799c8d75c113af5da24aa58b46 100644 +--- a/ipatests/test_integration/test_epn.py ++++ b/ipatests/test_integration/test_epn.py +@@ -180,7 +180,6 @@ def configure_starttls(host): + postconf(host, 'smtpd_tls_session_cache_timeout = 3600s') + # announce STARTTLS support to remote SMTP clients, not require + postconf(host, 'smtpd_tls_security_level = may') +- + host.run_command(["systemctl", "restart", "postfix"]) + + +@@ -208,6 +207,9 @@ def configure_ssl_client_cert(host): + # CA certificates of root CAs trusted to sign remote SMTP client cert + postconf(host, f"smtpd_tls_CAfile = {paths.IPA_CA_CRT}") + ++ if host.is_fips_mode: ++ postconf(host, 'smtpd_tls_fingerprint_digest = sha256') ++ + host.run_command(["systemctl", "restart", "postfix"]) + + +diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py +index 68a442a9cd7746eec728ee38fda34dbc5361c59b..bf4163abc0f138ed42c639eee3e95df52da43a71 100644 +--- a/ipatests/test_integration/test_installation.py ++++ b/ipatests/test_integration/test_installation.py +@@ -35,6 +35,7 @@ from ipatests.pytest_ipa.integration.env_config import get_global_config + from ipatests.test_integration.base import IntegrationTest + from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup + from ipatests.test_integration.test_cert import get_certmonger_fs_id ++from ipatests.pytest_ipa.integration import skip_if_fips + from ipaplatform import services + + +@@ -298,6 +299,7 @@ class TestInstallCA(IntegrationTest): + tasks.install_replica(self.master, self.replicas[1], setup_ca=False) + tasks.install_ca(self.replicas[1], extra_args=["--skip-schema-check"]) + ++ @skip_if_fips() + def test_certmonger_reads_token_HSM(self): + """Test if certmonger reads the token in HSM + +-- +2.41.0 + diff --git a/SOURCES/0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch b/SOURCES/0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch deleted file mode 100644 index 1e2912d..0000000 --- a/SOURCES/0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 392e60e3fa0e39a2e364268a21d869a2f3a85905 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 19 Jun 2023 19:04:32 +0200 -Subject: [PATCH] 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 ---- - ipatests/test_integration/test_upgrade.py | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/ipatests/test_integration/test_upgrade.py b/ipatests/test_integration/test_upgrade.py -index 9203503cdccf4478f9864bd487e458761e9a2a2f..182e3b5da3c758cc10913ad4eed119b0983fcc23 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) --- -2.41.0 - diff --git a/SOURCES/0007-The-PKI-JSON-API-the-revocation-reason-key-may-be-ca.patch b/SOURCES/0007-The-PKI-JSON-API-the-revocation-reason-key-may-be-ca.patch new file mode 100644 index 0000000..66d6c63 --- /dev/null +++ b/SOURCES/0007-The-PKI-JSON-API-the-revocation-reason-key-may-be-ca.patch @@ -0,0 +1,50 @@ +From d4271391adc45c781092db0fb89b802743a9dda8 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 11 Sep 2023 21:37:05 +0000 +Subject: [PATCH] The PKI JSON API the revocation reason key may be + case-sensitive + +PKI 11.4.0 changed the reason keyword in the REST API from lower-case +to camel-case in https://github.com/dogtagpki/pki/commit/926eb221ce6 + +Use Reason instead of reason as the keyword for revocations +for PKI 11.4.0+ + +Related: https://pagure.io/freeipa/issue/9345 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Thomas Woerner +--- + ipaserver/plugins/dogtag.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py +index 1c2c51824eecb71cfa8146ceb30435c5ad5d79c7..0036803c86652b557ebeb3cd048877bc01a6b71a 100644 +--- a/ipaserver/plugins/dogtag.py ++++ b/ipaserver/plugins/dogtag.py +@@ -274,6 +274,8 @@ if six.PY3: + + logger = logging.getLogger(__name__) + ++pki_version = pki.util.Version(pki.specification_version()) ++ + # These are general status return values used when + # CMSServlet.outputError() is invoked. + CMS_SUCCESS = 0 +@@ -1130,7 +1132,11 @@ class ra(rabase.rabase, RestClient): + serial_number = int(serial_number, 0) + + path = 'agent/certs/{}/revoke'.format(serial_number) +- data = '{{"reason":"{}"}}'.format(reasons[revocation_reason]) ++ if pki_version < pki.util.Version("11.4.0"): ++ keyword = "reason" ++ else: ++ keyword = "Reason" ++ data = '{{"{}":"{}"}}'.format(keyword, reasons[revocation_reason]) + + http_status, _http_headers, http_body = self._ssldo( + 'POST', path, +-- +2.41.0 + diff --git a/SOURCES/0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch b/SOURCES/0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch deleted file mode 100644 index 2877404..0000000 --- a/SOURCES/0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch +++ /dev/null @@ -1,129 +0,0 @@ -From f93a6d3ff52247ce5e582816fec689b8901fc984 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Wed, 14 Jun 2023 15:12:39 +0200 -Subject: [PATCH] Uninstaller: uninstall PKI before shutting down services - -The uninstaller is stopping all the services before -calling pkidestroy to uninstall the CA. -With PKI 11.4+ this sequence fails as pkidestroy tries -to connect to PKI server in order to unregister from the -security domain. The error interrupts the full completion -of pkidestroy, is logged but doesn't make ipa uninstallation -fail. -The issue is that trying to re-install later on would fail because -pkidestroy did not completely uninstall the CA. - -To avoid this, call pkidestroy before shutting down the services. -Also add an uninstall_check method that restarts IPA if it is -not running, and use pkidestroy --force to make sure that PKI -is uninstalled even if restart failed. - -Fixes: https://pagure.io/freeipa/issue/9330 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden ---- - ipaserver/install/ca.py | 18 ++++++++++++++++++ - ipaserver/install/dogtaginstance.py | 2 +- - ipaserver/install/kra.py | 2 ++ - ipaserver/install/server/install.py | 8 +++++--- - 4 files changed, 26 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py -index be0e732e8ff6966ccc0077d9339f9f0bc66ae6ec..c93ae1fce4c8848d493677eafee7952740e51631 100644 ---- a/ipaserver/install/ca.py -+++ b/ipaserver/install/ca.py -@@ -169,6 +169,24 @@ def print_ca_configuration(options): - - - def uninstall_check(options): -+ """IPA needs to be running so pkidestroy can unregister CA""" -+ ca = cainstance.CAInstance(api.env.realm) -+ if not ca.is_installed(): -+ return -+ -+ result = ipautil.run([paths.IPACTL, 'status'], -+ raiseonerr=False) -+ -+ if result.returncode not in [0, 4]: -+ try: -+ logger.info( -+ "Starting services to unregister CA from security domain") -+ ipautil.run([paths.IPACTL, 'start']) -+ except Exception: -+ logger.info("Re-starting IPA failed, continuing uninstall") -+ -+ -+def uninstall_crl_check(options): - """Check if the host is CRL generation master""" - # Skip the checks if the host is not a CA instance - ca = cainstance.CAInstance(api.env.realm) -diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py -index c2c6b3f49243f096448c178fafd09f429f0f46c8..4967aca01807e58dfcc3157af10b92eff5dba206 100644 ---- a/ipaserver/install/dogtaginstance.py -+++ b/ipaserver/install/dogtaginstance.py -@@ -305,7 +305,7 @@ class DogtagInstance(service.Service): - self.print_msg("Unconfiguring %s" % self.subsystem) - - args = [paths.PKIDESTROY, -- "-i", "pki-tomcat", -+ "-i", "pki-tomcat", "--force", - "-s", self.subsystem] - - # specify --log-file on PKI 11.0.0 or later -diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py -index 857c5165b808baee3f0815e78828fb899eb78a2d..59cbda812a853997752f7d932e0690e3a950aa1f 100644 ---- a/ipaserver/install/kra.py -+++ b/ipaserver/install/kra.py -@@ -132,6 +132,8 @@ def uninstall_check(options): - - if result.returncode not in [0, 4]: - try: -+ logger.info( -+ "Starting services to unregister KRA from security domain") - ipautil.run([paths.IPACTL, 'start']) - except Exception: - logger.info("Re-starting IPA failed, continuing uninstall") -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 4e4076410f1c1af188a0ab3606ef13be39702b7d..ccb958232935de2166f2d4867b626f59d7ba5333 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -1110,6 +1110,7 @@ def uninstall_check(installer): - raise ScriptError("Aborting uninstall operation.") - - kra.uninstall_check(options) -+ ca.uninstall_check(options) - - try: - api.Backend.ldap2.connect(autobind=True) -@@ -1132,7 +1133,7 @@ def uninstall_check(installer): - else: - dns.uninstall_check(options) - -- ca.uninstall_check(options) -+ ca.uninstall_crl_check(options) - - cleanup_dogtag_server_specific_data() - -@@ -1181,6 +1182,9 @@ def uninstall(installer): - # Uninstall the KRA prior to shutting the services down so it - # can un-register with the CA. - kra.uninstall() -+ # Uninstall the CA priori to shutting the services down so it -+ # can unregister from the security domain -+ ca.uninstall() - - print("Shutting down all IPA services") - try: -@@ -1194,8 +1198,6 @@ def uninstall(installer): - - restore_time_sync(sstore, fstore) - -- ca.uninstall() -- - dns.uninstall() - - httpinstance.HTTPInstance(fstore).uninstall() --- -2.41.0 - diff --git a/SOURCES/0008-WIP-Get-the-PKI-version-from-the-remote-to-determine.patch b/SOURCES/0008-WIP-Get-the-PKI-version-from-the-remote-to-determine.patch new file mode 100644 index 0000000..2f85e4f --- /dev/null +++ b/SOURCES/0008-WIP-Get-the-PKI-version-from-the-remote-to-determine.patch @@ -0,0 +1,102 @@ +From 0539d97f3e9d2b7d80549ff08d78fe55afcc2dbb Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 26 Oct 2023 13:59:21 -0400 +Subject: [PATCH] WIP: Get the PKI version from the remote to determine the + argument + +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Thomas Woerner +--- + ipaserver/plugins/dogtag.py | 55 ++++++++++++++++++++++++++++++++----- + 1 file changed, 48 insertions(+), 7 deletions(-) + +diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py +index 0036803c86652b557ebeb3cd048877bc01a6b71a..7cd51ae58ae0edfe69f0ac7fa190290e2669b0d2 100644 +--- a/ipaserver/plugins/dogtag.py ++++ b/ipaserver/plugins/dogtag.py +@@ -274,8 +274,6 @@ if six.PY3: + + logger = logging.getLogger(__name__) + +-pki_version = pki.util.Version(pki.specification_version()) +- + # These are general status return values used when + # CMSServlet.outputError() is invoked. + CMS_SUCCESS = 0 +@@ -1059,6 +1057,39 @@ class ra(rabase.rabase, RestClient): + + return cmd_result + ++ def get_pki_version(self): ++ """ ++ Retrieve the version of a remote PKI server. ++ ++ The REST API request is a GET to the info URI: ++ GET /pki/rest/info HTTP/1.1 ++ ++ The response is: {"Version":"11.5.0","Attributes":{"Attribute":[]}} ++ """ ++ path = "/pki/rest/info" ++ logger.debug('%s.get_pki_version()', type(self).__name__) ++ http_status, _http_headers, http_body = self._ssldo( ++ 'GET', path, ++ headers={ ++ 'Content-Type': 'application/json', ++ 'Accept': 'application/json', ++ }, ++ use_session=False, ++ ) ++ if http_status != 200: ++ self.raise_certificate_operation_error('get_pki_version', ++ detail=http_status) ++ ++ try: ++ response = json.loads(ipautil.decode_json(http_body)) ++ except ValueError as e: ++ logger.debug("Response from CA was not valid JSON: %s", e) ++ raise errors.RemoteRetrieveError( ++ reason=_("Response from CA was not valid JSON") ++ ) ++ ++ return response.get('Version') ++ + + def revoke_certificate(self, serial_number, revocation_reason=0): + """ +@@ -1125,6 +1156,20 @@ class ra(rabase.rabase, RestClient): + detail='7 is not a valid revocation reason' + ) + ++ # dogtag changed the argument case for revocation from ++ # "reason" to "Reason" in PKI 11.4.0. Detect that change ++ # based on the remote version and pass the expected value ++ # in. ++ pki_version = pki.util.Version(self.get_pki_version()) ++ if pki_version is None: ++ self.raise_certificate_operation_error('revoke_certificate', ++ detail="Remove version not " ++ "detected") ++ if pki_version < pki.util.Version("11.4.0"): ++ reason = "reason" ++ else: ++ reason = "Reason" ++ + # Convert serial number to integral type from string to properly handle + # radix issues. Note: the int object constructor will properly handle + # large magnitude integral values by returning a Python long type +@@ -1132,11 +1177,7 @@ class ra(rabase.rabase, RestClient): + serial_number = int(serial_number, 0) + + path = 'agent/certs/{}/revoke'.format(serial_number) +- if pki_version < pki.util.Version("11.4.0"): +- keyword = "reason" +- else: +- keyword = "Reason" +- data = '{{"{}":"{}"}}'.format(keyword, reasons[revocation_reason]) ++ data = '{{"{}":"{}"}}'.format(reason, reasons[revocation_reason]) + + http_status, _http_headers, http_body = self._ssldo( + 'POST', path, +-- +2.41.0 + diff --git a/SOURCES/0009-Detection-of-PKI-subsystem.patch b/SOURCES/0009-Detection-of-PKI-subsystem.patch deleted file mode 100644 index c85677a..0000000 --- a/SOURCES/0009-Detection-of-PKI-subsystem.patch +++ /dev/null @@ -1,44 +0,0 @@ -From b9a07b1e97ee4e310b50860103872685da540da4 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 19 Jun 2023 15:40:39 +0200 -Subject: [PATCH] Detection of PKI subsystem - -In order to know if ca/kra is installed locally, the code -is calling pki-server subsystem-show _subsystem_ -and ensures that "Enabled: True" is in the output. - -If a subsystem fails to start, the command returns -"Enabled: False" but it doesn't mean that the subsystem -is not installed, it just means that it is not active -right now. -Same output if the subsystem has been disabled with -pki-server subsystem-disable _subsystem_. - -The correct way to check if a subsystem is installed is to -ensure that subsystem-show does not exit on error and -contains "Enabled: ", whatever the value. - -Related: https://pagure.io/freeipa/issue/9330 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden ---- - ipaserver/install/dogtaginstance.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py -index 4967aca01807e58dfcc3157af10b92eff5dba206..7fdf2e0ed0f3ed99a6672f527d38dda0ce5ef8bb 100644 ---- a/ipaserver/install/dogtaginstance.py -+++ b/ipaserver/install/dogtaginstance.py -@@ -184,7 +184,7 @@ class DogtagInstance(service.Service): - ['pki-server', 'subsystem-show', self.subsystem.lower()], - capture_output=True) - # parse the command output -- return 'Enabled: True' in result.output -+ return 'Enabled: ' in result.output - except ipautil.CalledProcessError: - return False - --- -2.41.0 - diff --git a/SOURCES/0009-ipatests-fix-expected-output-for-ipahealthcheck.meta.patch b/SOURCES/0009-ipatests-fix-expected-output-for-ipahealthcheck.meta.patch new file mode 100644 index 0000000..eba1717 --- /dev/null +++ b/SOURCES/0009-ipatests-fix-expected-output-for-ipahealthcheck.meta.patch @@ -0,0 +1,48 @@ +From 411107e1d1fa64b15978b7c69522613fbf3aa827 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 29 Sep 2023 10:31:00 +0200 +Subject: [PATCH] ipatests: fix expected output for + ipahealthcheck.meta.services + +ipa-healthcheck commit 31be12b introduced a change in the output +message when pki-tomcatd is not running. +With versions <= 0.12, the service name is displayed as +pki_tomcatd (with an underscore), but with 0.13+ it is +pki-tomcatd (with a dash). + +Fixes: https://pagure.io/freeipa/issue/9460 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_ipahealthcheck.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 35fcfe10508589ded021207a4eba4fb0143495b4..5d79f2b529e819a291228776c4cc278463f02e59 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -454,6 +454,11 @@ class TestIpaHealthCheck(IntegrationTest): + assert data[0]["result"] == "SUCCESS" + assert data[0]["kw"]["status"] is True + ++ version = tasks.get_healthcheck_version(self.master) ++ # With healthcheck newer versions, the error msg for PKI tomcat ++ # contains the string pki-tomcatd instead of pki_tomcatd ++ always_replace = parse_version(version) >= parse_version("0.13") ++ + for service in svc_list: + restart_service(self.master, service) + returncode, data = run_healthcheck( +@@ -466,7 +471,7 @@ class TestIpaHealthCheck(IntegrationTest): + for check in data: + if check["check"] != service: + continue +- if service != 'pki_tomcatd': ++ if service != 'pki_tomcatd' or always_replace: + service = service.replace('_', '-') + assert check["result"] == "ERROR" + assert check["kw"]["msg"] == "%s: not running" % service +-- +2.41.0 + diff --git a/SOURCES/0010-Upgrade-fix-replica-agreement.patch b/SOURCES/0010-Upgrade-fix-replica-agreement.patch deleted file mode 100644 index 46dc830..0000000 --- a/SOURCES/0010-Upgrade-fix-replica-agreement.patch +++ /dev/null @@ -1,164 +0,0 @@ -From ad77c4c6512f82019d1970d910647761b60aaedb 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 c0cdd3eb19c486121f727476360ce421b1d82728..d963753d0bf9ee65285a86fa9a249198c28a66e2 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 - diff --git a/SOURCES/0010-ipatests-ignore-nsslapd-accesslog-logbuffering-WARN-.patch b/SOURCES/0010-ipatests-ignore-nsslapd-accesslog-logbuffering-WARN-.patch new file mode 100644 index 0000000..553c2cc --- /dev/null +++ b/SOURCES/0010-ipatests-ignore-nsslapd-accesslog-logbuffering-WARN-.patch @@ -0,0 +1,132 @@ +From 7e76329f76b7605ac6ec255c53b3c15d368a63f7 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 13 Nov 2023 09:48:09 -0500 +Subject: [PATCH] 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 +--- + .../test_integration/test_ipahealthcheck.py | 28 +++++++++++++++++++ + .../test_replica_promotion.py | 5 +++- + 2 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 5d79f2b529e819a291228776c4cc278463f02e59..278f75abdd772a59178a61e2ab63e3178fef2518 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -10,6 +10,7 @@ from __future__ import absolute_import + from configparser import RawConfigParser, NoOptionError + from datetime import datetime, timedelta, timezone + UTC = timezone.utc ++import io + import json + import os + import re +@@ -209,6 +210,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""" +@@ -266,6 +289,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): + """ +@@ -558,6 +582,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]) +@@ -698,6 +723,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 + ) +@@ -713,6 +739,7 @@ class TestIpaHealthCheck(IntegrationTest): + 'output_file=%s' % HC_LOG, + ]) + ) ++ set_excludes(self.master, "key", "DSCLE0004") + returncode, _unused = run_healthcheck( + self.master, config=config_file + ) +@@ -2408,6 +2435,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 d477c3a20df80f16d47a55c9359ce165049dd907..b71f2d5d7e1517ab73d79b62477a3377839b0b7a 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 = [ +-- +2.41.0 + diff --git a/SOURCES/0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch b/SOURCES/0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch deleted file mode 100644 index 27161d9..0000000 --- a/SOURCES/0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 3b58487c7b2f8ac133e37e8f90f85ff2fb05bf34 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 17092a49966e61d5a4a9b04c15abcb1de8be9683..d1e65ef7cc3e748670f2cdebe2a5cb7172af27f0 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/0011-ipatests-fix-expected-output-for-ipahealthcheck.ipa..patch b/SOURCES/0011-ipatests-fix-expected-output-for-ipahealthcheck.ipa..patch new file mode 100644 index 0000000..bd27617 --- /dev/null +++ b/SOURCES/0011-ipatests-fix-expected-output-for-ipahealthcheck.ipa..patch @@ -0,0 +1,45 @@ +From faf8be455a6ab4f5b1bed00a611e655535ed31e7 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 14 Nov 2023 13:21:30 -0500 +Subject: [PATCH] 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 +--- + ipatests/test_integration/test_ipahealthcheck.py | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 278f75abdd772a59178a61e2ab63e3178fef2518..785e9abbae3b807f100a3d875e0c0b23f868be83 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -635,9 +635,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]) +-- +2.41.0 + diff --git a/SOURCES/0012-group-add-member-fails-with-an-external-member.patch b/SOURCES/0012-group-add-member-fails-with-an-external-member.patch new file mode 100644 index 0000000..61339da --- /dev/null +++ b/SOURCES/0012-group-add-member-fails-with-an-external-member.patch @@ -0,0 +1,38 @@ +From bc69177ef80d1873026ad91a6e449b9cf20028b9 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 741f0608f93449f5a3959a47734f965ab484a1e5..7e585c87639db093222fe2cebca5c9094a22d7ce 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -303,7 +303,7 @@ class DomainValidator: + # 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')) + +-- +2.43.0 + diff --git a/SOURCES/0012-tests-fix-backup-restore-scenario-with-replica.patch b/SOURCES/0012-tests-fix-backup-restore-scenario-with-replica.patch deleted file mode 100644 index 3c188e3..0000000 --- a/SOURCES/0012-tests-fix-backup-restore-scenario-with-replica.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 5e291da42898cc646f699c21a44b03b833d346e8 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Tue, 27 Jun 2023 15:30:08 +0200 -Subject: [PATCH] tests: fix backup-restore scenario with replica - -The test TestBackupAndRestoreWithReplica is simulating a -master crash in order to check the behavior after ipa-restore. - -Since commit 67a33e5, the uninstaller restarts the services in -order to unregister the server from PKI security domain. An -indirect consequence is that master/replica communication is re- -established and operations removing entries (done by the uninstaller) -are replicated to the replica. -This means that the scenario does not really simulate a server crash. - -To make sure that no replication happens during this "crash", stop -the replica first, then uninstall the master, and finally restart -the replica before calling the ipa-restore command on the master. - -Fixes: https://pagure.io/freeipa/issue/9404 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden ---- - ipatests/test_integration/test_backup_and_restore.py | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/ipatests/test_integration/test_backup_and_restore.py b/ipatests/test_integration/test_backup_and_restore.py -index 390c065f373e9a8a667f228a09eebd9ac033a19f..83b6a6b44d805fb0615e2128d4be984c6f858bf9 100644 ---- a/ipatests/test_integration/test_backup_and_restore.py -+++ b/ipatests/test_integration/test_backup_and_restore.py -@@ -602,6 +602,12 @@ class TestBackupAndRestoreWithReplica(IntegrationTest): - tasks.user_add(self.replica1, 'test2_replica') - - # simulate master crash -+ # the replica is stopped to make sure master uninstallation -+ # does not delete any entry on the replica. In case of a -+ # real master crash there would not be any communication between -+ # master and replica -+ self.replica1.run_command(['ipactl', 'stop']) -+ - self.master.run_command(['ipactl', 'stop']) - tasks.uninstall_master(self.master, clean=False) - -@@ -612,6 +618,7 @@ class TestBackupAndRestoreWithReplica(IntegrationTest): - self.master.run_command([ - "systemctl", "disable", "oddjobd" - ]) -+ self.replica1.run_command(['ipactl', 'start']) - - self.master.run_command(['ipa-restore', '-U', backup_path]) - --- -2.41.0 - diff --git a/SOURCES/0013-Handle-samba-changes-in-samba.security.dom_sid.patch b/SOURCES/0013-Handle-samba-changes-in-samba.security.dom_sid.patch new file mode 100644 index 0000000..07196a0 --- /dev/null +++ b/SOURCES/0013-Handle-samba-changes-in-samba.security.dom_sid.patch @@ -0,0 +1,41 @@ +From c6623f9ce4e1bde729ed6f729da5981c9f26c728 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 7e585c87639db093222fe2cebca5c9094a22d7ce..675572c036e4ea5434d2c6808dd301b425229b38 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -97,7 +97,7 @@ logger = logging.getLogger(__name__) + def is_sid_valid(sid): + try: + security.dom_sid(sid) +- except TypeError: ++ except (TypeError, ValueError): + return False + else: + return True +@@ -457,7 +457,7 @@ class DomainValidator: + 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 ' +-- +2.43.0 + diff --git a/SOURCES/0013-OTP-fix-data-type-to-avoid-endianness-issue.patch b/SOURCES/0013-OTP-fix-data-type-to-avoid-endianness-issue.patch deleted file mode 100644 index e3dd65d..0000000 --- a/SOURCES/0013-OTP-fix-data-type-to-avoid-endianness-issue.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 631dd72369385b0793e5bc0e019c088b4f1e2bb3 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 26 Jun 2023 18:24:46 +0200 -Subject: [PATCH] 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 ---- - daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -index 937594117956d57540d4cf4eabeef6d22860aec8..45626523ffa1030cdff4f3e0ccdfa1618a51ccaf 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); --- -2.41.0 - diff --git a/SOURCES/0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch b/SOURCES/0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch deleted file mode 100644 index 693cfad..0000000 --- a/SOURCES/0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 1e8352486cd5f77ff79e18798f04f406baf0a9a1 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 9718c408b7f48dd78dc2abae32fb9ecb85445dfb..cca20983e65f99d5ba0bb7bc6dc2b5684a6f37d9 100644 ---- a/ipatests/test_integration/test_acme.py -+++ b/ipatests/test_integration/test_acme.py -@@ -10,6 +10,7 @@ import pytest - - 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 ipatests.test_integration.test_random_serial_numbers import ( -@@ -85,6 +86,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']) --- -2.41.0 - diff --git a/SOURCES/0014-test_install-restart-services-after-date-change.patch b/SOURCES/0014-test_install-restart-services-after-date-change.patch new file mode 100644 index 0000000..cd4bcd7 --- /dev/null +++ b/SOURCES/0014-test_install-restart-services-after-date-change.patch @@ -0,0 +1,43 @@ +From c7f999599efe9f3f237f8ad3b7c739714051e3e9 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 7 Dec 2023 08:35:45 +0100 +Subject: [PATCH] test_install: restart services after date change + +The test TestKRAinstallAfterCertRenew is moving the +date in the future in order to reach the grace period where +certmonger detects some certificates need to be renewed. +Restart the services after the date change. + +Fixes: https://pagure.io/freeipa/issue/9405 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Michal Polovka +--- + ipatests/test_integration/test_installation.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py +index bf4163abc0f138ed42c639eee3e95df52da43a71..02fa5bc56d63421c28a5dd1fa02f9f75d305e7bf 100644 +--- a/ipatests/test_integration/test_installation.py ++++ b/ipatests/test_integration/test_installation.py +@@ -1569,6 +1569,8 @@ class TestKRAinstallAfterCertRenew(IntegrationTest): + grace_date = cert_expiry - timedelta(days=10) + grace_date = datetime.strftime(grace_date, "%Y-%m-%d %H:%M:%S") + self.master.run_command(['date', '-s', grace_date]) ++ # restart service after date change ++ self.master.run_command(['ipactl', 'restart']) + + # get the count of certs track by certmonger + cmd = self.master.run_command(['getcert', 'list']) +@@ -1591,6 +1593,8 @@ class TestKRAinstallAfterCertRenew(IntegrationTest): + cert_expiry = cert_expiry + timedelta(days=3) + cert_expiry = datetime.strftime(cert_expiry, "%Y-%m-%d %H:%M:%S") + self.master.run_command(['date', '-s', cert_expiry]) ++ # restart service after date change ++ self.master.run_command(['ipactl', 'restart']) + + passwd = "{passwd}\n{passwd}\n{passwd}".format(passwd=admin_pass) + self.master.run_command(['kinit', 'admin'], stdin_text=passwd) +-- +2.43.0 + diff --git a/SOURCES/0015-Issue-9497-Add-new-password-policy-logging-function.patch b/SOURCES/0015-Issue-9497-Add-new-password-policy-logging-function.patch new file mode 100644 index 0000000..1512cfc --- /dev/null +++ b/SOURCES/0015-Issue-9497-Add-new-password-policy-logging-function.patch @@ -0,0 +1,40 @@ +From eabdbbc00613963deffe42ea17dfb0a690c62e3f Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:34:44 -0500 +Subject: [PATCH] Issue 9497 - Add new password policy logging function + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-slapi-plugins/common/util.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/daemons/ipa-slapi-plugins/common/util.h b/daemons/ipa-slapi-plugins/common/util.h +index 1eaf47facb717fe6a95d89fe02311205eabc3e96..db7cf7181ceaf710a5a082c4e80eb66567180be5 100644 +--- a/daemons/ipa-slapi-plugins/common/util.h ++++ b/daemons/ipa-slapi-plugins/common/util.h +@@ -30,7 +30,7 @@ + * Program may make changes or additions to the list of Approved + * Interfaces. + * +- * Copyright (C) 2010 Red Hat, Inc. ++ * Copyright (C) 2010-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -67,6 +67,10 @@ + "[file %s, line %d]: " fmt, \ + __FILE__, __LINE__, ##__VA_ARGS__) + ++#define LOG_PWDPOLICY(fmt, ...) \ ++ slapi_log_error(SLAPI_LOG_PWDPOLICY, log_func, fmt, ##__VA_ARGS__) ++ ++/* "Trace" logging is very expensive and should be avoided/replaced. TBD */ + #define LOG_TRACE(fmt, ...) \ + slapi_log_error(SLAPI_LOG_TRACE, log_func, fmt, ##__VA_ARGS__) + +-- +2.43.0 + diff --git a/SOURCES/0015-User-plugin-improve-error-related-to-non-existing-id.patch b/SOURCES/0015-User-plugin-improve-error-related-to-non-existing-id.patch deleted file mode 100644 index c92a18c..0000000 --- a/SOURCES/0015-User-plugin-improve-error-related-to-non-existing-id.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 387873080f1bc14aeaad89311b06dc46934be1ab Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Wed, 19 Jul 2023 13:24:55 +0200 -Subject: [PATCH] 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 ---- - ipaserver/plugins/baseuser.py | 6 +++++- - ipaserver/plugins/stageuser.py | 6 +++++- - ipaserver/plugins/user.py | 6 +++++- - 3 files changed, 15 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py -index 73b76d328a88639afd40bd261c8a35f324ec865b..ba5f9b7763662b32f238c0fb0ca548ff2f07db0d 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 51438a83a95d15fb320148d2934a52f13a38f390..852e51b0eb0d757940b84721a6f01e43c5f36dd2 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 643b44f141e3add76f95cbeec6e90fec0ad4c9ad..a337e1fc7b44ef41ad16e18bd965b7af0a767d05 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, --- -2.41.0 - diff --git a/SOURCES/0016-Issue-9497-Update-logging-in-ipa_enrollment.patch b/SOURCES/0016-Issue-9497-Update-logging-in-ipa_enrollment.patch new file mode 100644 index 0000000..ae5ef17 --- /dev/null +++ b/SOURCES/0016-Issue-9497-Update-logging-in-ipa_enrollment.patch @@ -0,0 +1,68 @@ +From 7e31f111c83bed966157b0660e9640e18450b1a2 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:36:49 -0500 +Subject: [PATCH] Issue 9497 - Update logging in ipa_enrollment + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + .../ipa-enrollment/ipa_enrollment.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-enrollment/ipa_enrollment.c b/daemons/ipa-slapi-plugins/ipa-enrollment/ipa_enrollment.c +index 26cbb69d713767909fd62fb77e7defdd323ec7ac..b72ad5ef1c81997d89b2f94528da516b5df3d285 100644 +--- a/daemons/ipa-slapi-plugins/ipa-enrollment/ipa_enrollment.c ++++ b/daemons/ipa-slapi-plugins/ipa-enrollment/ipa_enrollment.c +@@ -30,7 +30,7 @@ + * Program may make changes or additions to the list of Approved + * Interfaces. + * +- * Copyright (C) 2005 Red Hat, Inc. ++ * Copyright (C) 2005-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -132,7 +132,8 @@ ipa_join(Slapi_PBlock *pb) + Slapi_DN *sdn; + Slapi_Backend *be; + Slapi_Entry **es = NULL; +- int rc=0, ret=0, res, i; ++ int rc=0, ret=0, res; ++ size_t i; + int is_root=0; + char *krbLastPwdChange = NULL; + char *fqdn = NULL; +@@ -204,7 +205,7 @@ ipa_join(Slapi_PBlock *pb) + + /* if there is none or more than one, freak out */ + if (i != 1) { +- LOG_TRACE("Too many entries, or entry no found (%d)", i); ++ LOG_TRACE("Too many entries, or entry no found (%lu)\n", i); + if (i == 0) + errMesg = "Host not found.\n"; + else +@@ -217,7 +218,7 @@ ipa_join(Slapi_PBlock *pb) + /* Is this host already enrolled? */ + krbLastPwdChange = slapi_entry_attr_get_charptr(targetEntry, "krbLastPwdChange"); + if (NULL != krbLastPwdChange) { +- LOG_TRACE("Host already enrolled"); ++ LOG_TRACE("Host already enrolled\n"); + errMesg = "Host already enrolled.\n"; + rc = LDAP_OPERATIONS_ERROR; + goto free_and_return; +@@ -313,8 +314,8 @@ done: + ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, JOIN_OID); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &retbval); + if (ret) { +- errMesg = "Could not set return values"; +- LOG("%s\n", errMesg); ++ errMesg = "Could not set return values\n"; ++ LOG("%s", errMesg); + rc = SLAPI_PLUGIN_EXTENDED_SENT_RESULT; + } + +-- +2.43.0 + diff --git a/SOURCES/0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch b/SOURCES/0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch deleted file mode 100644 index e5bae94..0000000 --- a/SOURCES/0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch +++ /dev/null @@ -1,122 +0,0 @@ -From caacccc6b92c08f510fba2e31d9c56eb372abddc Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Wed, 19 Jul 2023 13:28:43 +0200 -Subject: [PATCH] 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 ---- - ipatests/test_xmlrpc/test_stageuser_plugin.py | 20 +++++++++++++++ - ipatests/test_xmlrpc/test_user_plugin.py | 25 +++++++++++++++++++ - 2 files changed, 45 insertions(+) - -diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py -index 394015f87f9f4bd275a15bab930e28f16b299274..9ae5561dfa4e0d54fe1231501bfea3c0ba261849 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' - -@@ -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 8ac19a4f9ce4f341838282ecd3ed1bb491ac7004..baa28672e7552140a703ecdfa5772b445298cb37 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): --- -2.41.0 - diff --git a/SOURCES/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch b/SOURCES/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch deleted file mode 100644 index 08b2092..0000000 --- a/SOURCES/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 421e8e9ac886c50b4bb463a62b8ad5de8da94f31 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Mon, 26 Jun 2023 13:06:51 -0400 -Subject: [PATCH] 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 ---- - .../ipa-otp-lasttoken/ipa_otp_lasttoken.c | 38 +++++++++++++------ - daemons/ipa-slapi-plugins/libotp/otp_token.c | 1 + - 2 files changed, 27 insertions(+), 12 deletions(-) - -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 b7a2ba7f012fdbf90284ee6605788e196aa4793b..11106b239f9de9074125979cfae7c02e434936e1 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 a3cbfb0621c071f8addb29f7ce02f870a807c61d..4be4ede07cbbd0d26bcc9952ef4d84d777076ae7 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; - } --- -2.41.0 - diff --git a/SOURCES/0017-Issue-9497-update-debug-logging-in-ipa_graceperiod.patch b/SOURCES/0017-Issue-9497-update-debug-logging-in-ipa_graceperiod.patch new file mode 100644 index 0000000..e375136 --- /dev/null +++ b/SOURCES/0017-Issue-9497-update-debug-logging-in-ipa_graceperiod.patch @@ -0,0 +1,47 @@ +From e4aebc121c9242390da86fe6bda3e8c28edfb746 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:37:41 -0500 +Subject: [PATCH] Issue 9497 - update debug logging in ipa_graceperiod + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c b/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c +index 345e1dee7d163167373ca82dedb1e827f0e1bc8c..7a2d4f2aaea677d1fb3553fe49e6aa17c3e7a38c 100644 +--- a/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c ++++ b/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c +@@ -30,7 +30,7 @@ + * Program may make changes or additions to the list of Approved + * Interfaces. + * +- * Copyright (C) 2022 Red Hat, Inc. ++ * Copyright (C) 2022-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -447,7 +447,7 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb) + LOG_TRACE("grace limit disabled, skipping\n"); + goto done; + } else if (grace_limit < -1) { +- LOG_FATAL("Invalid passwordGraceLimit value %d\n", grace_limit); ++ LOG_FATAL("Invalid passwordGraceLimit value %ld\n", grace_limit); + return LDAP_OPERATIONS_ERROR; + } + +@@ -480,7 +480,7 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb) + slapi_pwpolicy_make_response_control(pb, -1, grace_limit - grace_user_time , -1); + } + } else if (grace_user_time >= grace_limit) { +- LOG_TRACE("%s password is expired and out of grace limit\n", dn); ++ LOG_PWDPOLICY("%s password is expired and out of grace limit\n", dn); + errstr = "Password is expired.\n"; + ret = LDAP_INVALID_CREDENTIALS; + +-- +2.43.0 + diff --git a/SOURCES/0018-Issue-9497-update-debug-logging-in-ipa_lockout.patch b/SOURCES/0018-Issue-9497-update-debug-logging-in-ipa_lockout.patch new file mode 100644 index 0000000..ae8554f --- /dev/null +++ b/SOURCES/0018-Issue-9497-update-debug-logging-in-ipa_lockout.patch @@ -0,0 +1,46 @@ +From be805c1150fd0c2e6ac2276f8535b14d57557aad Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:38:47 -0500 +Subject: [PATCH] Issue 9497 - update debug logging in ipa_lockout + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c +index a8095ccd371bfd29e3148ab2ad8c982a08f0b7e0..366018094bdc42c914d7743a89519ba1e1a6e124 100644 +--- a/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c ++++ b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c +@@ -30,7 +30,7 @@ + * Program may make changes or additions to the list of Approved + * Interfaces. + * +- * Copyright (C) 2010 Red Hat, Inc. ++ * Copyright (C) 2010-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -823,13 +823,15 @@ static int ipalockout_preop(Slapi_PBlock *pb) + if (failedcount >= max_fail) { + if (lockout_duration == 0) { + errstr = "Entry permanently locked.\n"; ++ LOG_PWDPOLICY("Entry '%s' is permanently locked.\n", dn); + ret = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + if (time_now < last_failed + lockout_duration) { + /* Too many failures */ +- LOG_TRACE("Too many failed logins. %lu out of %d\n", failedcount, max_fail); ++ LOG_PWDPOLICY("Too many failed logins for '%s'. %lu out of %d\n", ++ dn, failedcount, max_fail); + errstr = "Too many failed logins.\n"; + ret = LDAP_UNWILLING_TO_PERFORM; + } +-- +2.43.0 + diff --git a/SOURCES/0018-Prevent-the-admin-user-from-being-deleted.patch b/SOURCES/0018-Prevent-the-admin-user-from-being-deleted.patch deleted file mode 100644 index ee01e45..0000000 --- a/SOURCES/0018-Prevent-the-admin-user-from-being-deleted.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 4b02322fc786ee9caaa0380659507a2cec0d4101 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Thu, 25 May 2023 18:24:29 -0400 -Subject: [PATCH] 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 ---- - ipaserver/plugins/user.py | 19 +++++++++-- - ipatests/test_xmlrpc/test_user_plugin.py | 40 ++++++++++++------------ - 2 files changed, 37 insertions(+), 22 deletions(-) - -diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py -index a337e1fc7b44ef41ad16e18bd965b7af0a767d05..6f5e34917e1b838a463dee146a4e9390f20c130a 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 baa28672e7552140a703ecdfa5772b445298cb37..df105a23529b29944411a6418e5db55d56e2c72a 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): --- -2.41.0 - diff --git a/SOURCES/0019-Issue-9497-update-debug-logging-in-ipa_modrdn.patch b/SOURCES/0019-Issue-9497-update-debug-logging-in-ipa_modrdn.patch new file mode 100644 index 0000000..df1c28a --- /dev/null +++ b/SOURCES/0019-Issue-9497-update-debug-logging-in-ipa_modrdn.patch @@ -0,0 +1,56 @@ +From 473b1e465ba93ec313bc7cea62bb8d545f37e8bd Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:39:14 -0500 +Subject: [PATCH] Issue 9497 - update debug logging in ipa_modrdn + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c b/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c +index 6cec5f242b7d23d3752e5bc30c67e034abc96abb..8be192a5e94211f94a7f3a8a62409250b723ddb5 100644 +--- a/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c ++++ b/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c +@@ -30,7 +30,7 @@ + * Program may make changes or additions to the list of Approved + * Interfaces. + * +- * Copyright (C) 2010 Red Hat, Inc. ++ * Copyright (C) 2010-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -350,7 +350,6 @@ ipamodrdn_load_plugin_config(void) + { + int status = EOK; + int result; +- int i; + Slapi_PBlock *search_pb; + Slapi_Entry **entries = NULL; + +@@ -379,7 +378,7 @@ ipamodrdn_load_plugin_config(void) + goto cleanup; + } + +- for (i = 0; (entries[i] != NULL); i++) { ++ for (size_t i = 0; (entries[i] != NULL); i++) { + /* We don't care about the status here because we may have + * some invalid config entries, but we just want to continue + * looking for valid ones. */ +@@ -680,7 +679,8 @@ ipamodrdn_change_attr(struct configEntry *cfgentry, + slapi_modify_internal_pb(mod_pb); + slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &ret); + if (ret != LDAP_SUCCESS) { +- LOG_FATAL("Failed to change attribute with error %d\n", ret); ++ LOG_FATAL("Failed to change attribute '%s' in '%s' with error %d\n", ++ cfgentry->tattr, targetdn, ret); + ret = EFAIL; + } + ret = EOK; +-- +2.43.0 + diff --git a/SOURCES/0019-ipa-kdb-fix-error-handling-of-is_master_host.patch b/SOURCES/0019-ipa-kdb-fix-error-handling-of-is_master_host.patch deleted file mode 100644 index 957d97f..0000000 --- a/SOURCES/0019-ipa-kdb-fix-error-handling-of-is_master_host.patch +++ /dev/null @@ -1,87 +0,0 @@ -From fd32e6a3d95f28d2d11d41ee5dabb0d563cb5d51 Mon Sep 17 00:00:00 2001 -From: Julien Rische -Date: Mon, 31 Jul 2023 11:26:43 +0200 -Subject: [PATCH] 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 ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 41 +++++++++++++++++++-------------- - 1 file changed, 24 insertions(+), 17 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 83b507cb422c735f933edaebfc7b903b8fa908e4..1558e2bead288d9d00014e9b3b059934e80b54e4 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) { --- -2.41.0 - diff --git a/SOURCES/0020-Issue-9497-update-debug-logging-in-ipa_otp_counter.patch b/SOURCES/0020-Issue-9497-update-debug-logging-in-ipa_otp_counter.patch new file mode 100644 index 0000000..5713c8a --- /dev/null +++ b/SOURCES/0020-Issue-9497-update-debug-logging-in-ipa_otp_counter.patch @@ -0,0 +1,82 @@ +From 0f78feeca51a7abe49fbabf22991bf89eba7b12a Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:39:47 -0500 +Subject: [PATCH] Issue 9497 - update debug logging in ipa_otp_counter + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + .../ipa-otp-counter/ipa_otp_counter.c | 13 +++++++++---- + daemons/ipa-slapi-plugins/ipa-otp-counter/ldapmod.h | 4 +++- + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c b/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c +index da047d7dc58e27b37ad29c39bde44e33602ab4c5..5e03450c5164ee450736fc61b40ef769bc4572dd 100644 +--- a/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c ++++ b/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c +@@ -33,7 +33,7 @@ + * Authors: + * Nathaniel McCallum + * +- * Copyright (C) 2014 Red Hat, Inc. ++ * Copyright (C) 2014-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -295,14 +295,16 @@ preop_mod(Slapi_PBlock *pb) + } + + if (!simulate(mods, attr, cpre, &cpost) && repl == 0) { +- msg = slapi_ch_smprintf("Invalid operation sequence on %s", attr); ++ msg = slapi_ch_smprintf("Invalid operation sequence on %s (%s)", ++ attr, slapi_entry_get_dn_const(epre)); + goto error; + } + + if (cpost < cpre) { + if (repl == 0) { +- msg = slapi_ch_smprintf("Will not %s %s", +- cpost == COUNTER_UNSET ? "delete" : "decrement", attr); ++ msg = slapi_ch_smprintf("Will not %s %s (%s)", ++ cpost == COUNTER_UNSET ? "delete" : "decrement", ++ attr, slapi_entry_get_dn_const(epre)); + goto error; + } + +@@ -321,6 +323,9 @@ preop_mod(Slapi_PBlock *pb) + + error: + rc = LDAP_UNWILLING_TO_PERFORM; ++ if (msg) { ++ LOG("%s - error %d\n", msg, rc); ++ } + slapi_send_ldap_result(pb, rc, NULL, msg, 0, NULL); + if (slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc)) { + LOG_FATAL("slapi_pblock_set failed!\n"); +diff --git a/daemons/ipa-slapi-plugins/ipa-otp-counter/ldapmod.h b/daemons/ipa-slapi-plugins/ipa-otp-counter/ldapmod.h +index 45f43904b2288a97802ad2d698a30be972e2d8b7..324107c487f53e11774c51f248b00043e44b0bcc 100644 +--- a/daemons/ipa-slapi-plugins/ipa-otp-counter/ldapmod.h ++++ b/daemons/ipa-slapi-plugins/ipa-otp-counter/ldapmod.h +@@ -33,7 +33,7 @@ + * Authors: + * Nathaniel McCallum + * +- * Copyright (C) 2014 Red Hat, Inc. ++ * Copyright (C) 2014-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -41,6 +41,8 @@ + + #include + ++#define IPA_PLUGIN_NAME "ipa-otp-counter" ++ + long long + ldapmod_get_value(const LDAPMod *mod, long long def); + +-- +2.43.0 + diff --git a/SOURCES/0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch b/SOURCES/0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch deleted file mode 100644 index 17ad7c5..0000000 --- a/SOURCES/0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 13d5e88eb4ebb7a0132cbb050a9d230304ecbcff Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Wed, 2 Aug 2023 15:41:57 +0200 -Subject: [PATCH] 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 ---- - ipatests/test_webui/test_user.py | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py -index 8d44fbdb9380c94058307b02a96299d0e178cdc7..a8a92d00c7e1f40ef10eb9133cea8752daafe730 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' --- -2.41.0 - diff --git a/SOURCES/0021-Issue-9497-update-debug-logging-in-ipa_otp_lasttoken.patch b/SOURCES/0021-Issue-9497-update-debug-logging-in-ipa_otp_lasttoken.patch new file mode 100644 index 0000000..1d82729 --- /dev/null +++ b/SOURCES/0021-Issue-9497-update-debug-logging-in-ipa_otp_lasttoken.patch @@ -0,0 +1,96 @@ +From 5eb6af01873d0f70ff5b02c972867877da8e7c50 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:40:13 -0500 +Subject: [PATCH] Issue 9497 - update debug logging in ipa_otp_lasttoken + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + .../ipa-otp-lasttoken/ipa_otp_lasttoken.c | 25 ++++++++++++------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +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 11106b239f9de9074125979cfae7c02e434936e1..c1318f8eb19a5ff7da016eb145eece2f56925235 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 +@@ -33,7 +33,7 @@ + * Authors: + * Nathaniel McCallum + * +- * Copyright (C) 2013 Red Hat, Inc. ++ * Copyright (C) 2013-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -46,7 +46,7 @@ + + #include "util.h" + +-#define PLUGIN_NAME "ipa-otp-lasttoken" ++#define IPA_PLUGIN_NAME "ipa-otp-lasttoken" + #define OTP_CONTAINER "cn=otp,%s" + + static struct otp_config *otp_config; +@@ -191,9 +191,14 @@ static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr) + + static int preop_del(Slapi_PBlock *pb) + { ++ char *dn = NULL; ++ + if (is_allowed(pb, NULL)) + return 0; + ++ slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn); ++ LOG("Can't delete last active token (%s)", dn); ++ + return send_error(pb, LDAP_UNWILLING_TO_PERFORM, + "Can't delete last active token"); + } +@@ -221,10 +226,12 @@ static int preop_mod(Slapi_PBlock *pb) + return 0; + + /* If a protected attribute is modified, deny. */ +- for (int i = 0; mods != NULL && mods[i] != NULL; i++) { +- for (int j = 0; errors[j].attr != NULL; j++) { +- if (strcasecmp(mods[i]->mod_type, errors[j].attr) == 0) ++ for (size_t i = 0; mods != NULL && mods[i] != NULL; i++) { ++ for (size_t j = 0; errors[j].attr != NULL; j++) { ++ if (strcasecmp(mods[i]->mod_type, errors[j].attr) == 0) { ++ LOG("%s (%s)", errors[j].msg, slapi_entry_get_dn_const(entry)); + return send_error(pb, LDAP_UNWILLING_TO_PERFORM, errors[j].msg); ++ } + } + } + +@@ -284,7 +291,7 @@ static int ipa_otp_lasttoken_start(Slapi_PBlock *pb) + int ipa_otp_lasttoken_init(Slapi_PBlock *pb) + { + static const Slapi_PluginDesc preop_desc = { +- PLUGIN_NAME, ++ IPA_PLUGIN_NAME, + "FreeIPA", + "FreeIPA/1.0", + "Protect the user's last active token" +@@ -297,14 +304,14 @@ int ipa_otp_lasttoken_init(Slapi_PBlock *pb) + ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); + ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &preop_desc); + ret |= slapi_register_plugin("betxnpreoperation", 1, __func__, preop_init, +- PLUGIN_NAME " betxnpreoperation", NULL, ++ IPA_PLUGIN_NAME " betxnpreoperation", NULL, + ipa_otp_lasttoken_plugin_id); + ret |= slapi_register_plugin("postoperation", 1, __func__, postop_init, +- PLUGIN_NAME " postoperation", NULL, ++ IPA_PLUGIN_NAME " postoperation", NULL, + ipa_otp_lasttoken_plugin_id); + ret |= slapi_register_plugin("internalpostoperation", 1, __func__, + intpostop_init, +- PLUGIN_NAME " internalpostoperation", NULL, ++ IPA_PLUGIN_NAME " internalpostoperation", NULL, + ipa_otp_lasttoken_plugin_id); + ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, + (void *)ipa_otp_lasttoken_start); +-- +2.43.0 + diff --git a/SOURCES/0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch b/SOURCES/0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch deleted file mode 100644 index 1a01ef2..0000000 --- a/SOURCES/0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch +++ /dev/null @@ -1,70 +0,0 @@ -From ff6cfcacd67a0461a0341e17854732cbe301f1d6 Mon Sep 17 00:00:00 2001 -From: Mohammad Rizwan -Date: Wed, 2 Aug 2023 12:48:40 +0530 -Subject: [PATCH] ipatests: remove fixture call and wait to get things settle - -system date moved in order to expire the certs. Sometime it -is observed that subsequent operation fails with 500 error for CA, -hence restart the services after moving date and wait for sometime -to get things settle. - -Also the tests was calling fixture which is not required for it, hence -removed it as well. - -Fixes: https://pagure.io/freeipa/issue/9348 - -Signed-off-by: Mohammad Rizwan -Reviewed-By: Florence Blanc-Renaud ---- - ipatests/test_integration/test_acme.py | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py -index cca20983e65f99d5ba0bb7bc6dc2b5684a6f37d9..c7389732cd067d49541cd04ea6687a6b95b4669f 100644 ---- a/ipatests/test_integration/test_acme.py -+++ b/ipatests/test_integration/test_acme.py -@@ -606,6 +606,11 @@ def issue_and_expire_acme_cert(): - tasks.kdestroy_all(host) - tasks.move_date(host, 'stop', '+90days+60minutes') - -+ # restart ipa services as date moved and wait to get things settle -+ time.sleep(10) -+ master.run_command(['ipactl', 'restart']) -+ time.sleep(10) -+ - tasks.get_kdcinfo(master) - # Note raiseonerr=False: - # the assert is located after kdcinfo retrieval. -@@ -627,6 +632,11 @@ def issue_and_expire_acme_cert(): - for host in hosts: - tasks.move_date(host, 'start', '-90days-60minutes') - -+ # restart ipa services as date moved and wait to get things settle -+ time.sleep(10) -+ hosts[0].run_command(['ipactl', 'restart']) -+ time.sleep(10) -+ - - class TestACMERenew(IntegrationTest): - -@@ -960,7 +970,7 @@ class TestACMEPrune(IntegrationTest): - ) - assert f'Number of entries returned {no_of_cert - search_size_limit}' - -- def test_prune_config_show(self, issue_and_expire_acme_cert): -+ def test_prune_config_show(self): - """Test to check config-show command shows set param""" - if (tasks.get_pki_version(self.master) - < tasks.parse_version('11.3.0')): -@@ -1001,7 +1011,7 @@ class TestACMEPrune(IntegrationTest): - assert 'Request Search Time Limit: 0' in result.stdout_text - assert 'cron Schedule: 0 0 1 * *' in result.stdout_text - -- def test_prune_disable(self, issue_and_expire_acme_cert): -+ def test_prune_disable(self): - """Test prune command throw error after disabling the pruning""" - if (tasks.get_pki_version(self.master) - < tasks.parse_version('11.3.0')): --- -2.41.0 - diff --git a/SOURCES/0022-Issue-9497-update-debug-logging-in-ipa-pwd-extop.patch b/SOURCES/0022-Issue-9497-update-debug-logging-in-ipa-pwd-extop.patch new file mode 100644 index 0000000..602b81c --- /dev/null +++ b/SOURCES/0022-Issue-9497-update-debug-logging-in-ipa-pwd-extop.patch @@ -0,0 +1,766 @@ +From 3a8fe8c3a9de8d0e17ab4064ac689bce2b4b5042 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:41:10 -0500 +Subject: [PATCH] Issue 9497 - update debug logging in ipa-pwd-extop + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + .../ipa-slapi-plugins/ipa-pwd-extop/common.c | 25 +++-- + .../ipa-pwd-extop/encoding.c | 5 +- + .../ipa-pwd-extop/ipa_pwd_extop.c | 106 ++++++++++-------- + .../ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 59 +++++----- + 4 files changed, 105 insertions(+), 90 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +index 5251713c68855e10b0980af71696d944e683ae90..d30764bb2a05c7ca4a33ea114a2dc19af39e216f 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +@@ -33,7 +33,7 @@ + * Authors: + * Simo Sorce + * +- * Copyright (C) 2007-2010 Red Hat, Inc. ++ * Copyright (C) 2007-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -81,7 +81,8 @@ static struct ipapwd_krbcfg *ipapwd_getConfig(void) + char **encsalts; + char **tmparray; + char *tmpstr; +- int i, ret; ++ int ret; ++ size_t i; + + config = calloc(1, sizeof(struct ipapwd_krbcfg)); + if (!config) { +@@ -327,7 +328,8 @@ int ipapwd_getPolicy(const char *dn, + "ipaPwdUserCheck", NULL}; + Slapi_Entry **es = NULL; + Slapi_Entry *pe = NULL; +- int ret, res, scope, i; ++ int ret, res, scope; ++ size_t i; + int buffer_flags=0; + Slapi_ValueSet* results = NULL; + char *actual_type_name = NULL; +@@ -545,7 +547,7 @@ int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg, + } + sdn = slapi_sdn_new_dn_byref(dn); + if (!sdn) { +- LOG_FATAL("Unable to convert dn to sdn %s", dn ? dn : ""); ++ LOG_FATAL("Unable to convert dn to sdn %s\n", dn ? dn : ""); + *errMesg = "Internal Error"; + rc = LDAP_OPERATIONS_ERROR; + goto done; +@@ -564,7 +566,7 @@ int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg, + /* get the kerberos context and master key */ + *config = ipapwd_getConfig(); + if (NULL == *config) { +- LOG_FATAL("Error Retrieving Master Key"); ++ LOG_FATAL("Error Retrieving Master Key\n"); + *errMesg = "Fatal Internal Error"; + rc = LDAP_OPERATIONS_ERROR; + } +@@ -594,7 +596,7 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data) + /* Find the entry with the password policy */ + ret = ipapwd_getPolicy(data->dn, data->target, &pol); + if (ret) { +- LOG_TRACE("No password policy, use defaults"); ++ LOG_TRACE("No password policy, use defaults\n"); + } + break; + case IPA_CHANGETYPE_ADMIN: +@@ -620,14 +622,14 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data) + */ + ret = ipapwd_getPolicy(data->dn, data->target, &tmppol); + if (ret) { +- LOG_TRACE("No password policy, use defaults"); ++ LOG_TRACE("No password policy, use defaults\n"); + } else { + pol.max_pwd_life = tmppol.max_pwd_life; + pol.history_length = tmppol.history_length; + } + break; + default: +- LOG_TRACE("Unknown password change type, use defaults"); ++ LOG_TRACE("Unknown password change type, use defaults\n"); + break; + } + +@@ -860,7 +862,7 @@ int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg, + case IPA_CHANGETYPE_DSMGR: + case IPA_CHANGETYPE_ADMIN: + /* Mark as administratively reset which will unlock acct */ +- ret = ipapwd_setdate(data->target, smods, ++ ret = ipapwd_setdate(data->target, smods, + "krbLastAdminUnlock", + data->timeNow, false); + if (ret != LDAP_SUCCESS) +@@ -951,7 +953,7 @@ Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods, + char **new_pwd_history = NULL; + int n = 0; + int ret; +- int i; ++ size_t i; + + pwd_history = slapi_entry_attr_get_charray(data->target, + "passwordHistory"); +@@ -1083,10 +1085,9 @@ int ipapwd_set_extradata(const char *dn, + void ipapwd_free_slapi_value_array(Slapi_Value ***svals) + { + Slapi_Value **sv = *svals; +- int i; + + if (sv) { +- for (i = 0; sv[i]; i++) { ++ for (size_t i = 0; sv[i]; i++) { + slapi_value_free(&sv[i]); + } + } +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c +index 7b2f341229b4f3bf48105c3856c0d6778da154a5..43ae6f0a645c8f3ff0fa2d147891f93efff0eb20 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c +@@ -33,7 +33,7 @@ + * Authors: + * Simo Sorce + * +- * Copyright (C) 2007-2010 Red Hat, Inc. ++ * Copyright (C) 2007-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -231,7 +231,7 @@ int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg, + + if (!*svals) { + /* errMesg should have been set in encrypt_encode_key() */ +- LOG_FATAL("key encryption/encoding failed\n"); ++ LOG_FATAL("key encryption/encoding failed (%s)\n", *errMesg); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } +@@ -267,6 +267,7 @@ int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg, + } + (*ntvals)[0] = slapi_value_new(); + if (slapi_value_set((*ntvals)[0], nt_key, 16) == NULL) { ++ LOG("Failed to set value for nt_key"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +index 0d630ca04c38b739bb0d8bf22c162af9d3e15566..43c31becae45c1c91c7c2adf498aedbd05af9a69 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +@@ -33,7 +33,7 @@ + * Authors: + * Simo Sorce + * +- * Copyright (C) 2007-2010 Red Hat, Inc. ++ * Copyright (C) 2007-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -108,7 +108,7 @@ static void filter_keys(struct ipapwd_krbcfg *krbcfg, + struct ipapwd_keyset *kset, + bool allow_nthash) + { +- int i, j; ++ size_t i, j; + + for (i = 0; i < kset->num_keys; i++) { + for (j = 0; j < krbcfg->num_supp_encsalts; j++) { +@@ -151,11 +151,11 @@ static void filter_enctypes(struct ipapwd_krbcfg *krbcfg, + bool allow_nthash) + { + /* first filter for duplicates */ +- for (int i = 0; i + 1 < *num_kenctypes; i++) { +- for (int j = i + 1; j < *num_kenctypes; j++) { ++ for (size_t i = 0; i + 1 < *num_kenctypes; i++) { ++ for (size_t j = i + 1; j < *num_kenctypes; j++) { + if (kenctypes[i].ks_enctype == kenctypes[j].ks_enctype) { + /* duplicate, filter out */ +- for (int k = j; k + 1 < *num_kenctypes; k++) { ++ for (size_t k = j; k + 1 < *num_kenctypes; k++) { + kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype; + kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype; + } +@@ -166,8 +166,8 @@ static void filter_enctypes(struct ipapwd_krbcfg *krbcfg, + } + + /* then filter for supported */ +- for (int i = 0; i < *num_kenctypes; i++) { +- int j; ++ for (size_t i = 0; i < *num_kenctypes; i++) { ++ size_t j; + + /* Check if supported */ + for (j = 0; j < krbcfg->num_supp_encsalts; j++) { +@@ -184,7 +184,7 @@ static void filter_enctypes(struct ipapwd_krbcfg *krbcfg, + } + if (j == krbcfg->num_supp_encsalts) { + /* Unsupported, filter out */ +- for (int k = i; k + 1 < *num_kenctypes; k++) { ++ for (size_t k = i; k + 1 < *num_kenctypes; k++) { + kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype; + kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype; + } +@@ -344,6 +344,8 @@ parse_req_done: + + rc = ipapwd_check_max_pwd_len(strlen(newPasswd), &errMesg); + if (rc) { ++ LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n", ++ bindDN, errMesg); + goto free_and_return; + } + +@@ -456,7 +458,7 @@ parse_req_done: + char *cur_pw; + + if (oldPasswd == NULL || *oldPasswd == '\0') { +- LOG_FATAL("Old password was not provided!\n"); ++ LOG_FATAL("Old password was not provided for '%s'!\n", dn); + rc = LDAP_INVALID_CREDENTIALS; + goto free_and_return; + } +@@ -466,7 +468,7 @@ parse_req_done: + cur_pw = slapi_entry_attr_get_charptr(targetEntry, + "userPassword"); + if (!cur_pw) { +- LOG_FATAL("User has no current password?\n"); ++ LOG_FATAL("User '%s' does not have a current password?\n", dn); + rc = LDAP_UNWILLING_TO_PERFORM; + goto free_and_return; + } +@@ -485,7 +487,7 @@ parse_req_done: + slapi_value_free(&pw); + + if (ret != 0) { +- LOG_TRACE("Invalid password!\n"); ++ LOG_TRACE("Invalid password for '%s'!\n", dn); + rc = LDAP_INVALID_CREDENTIALS; + goto free_and_return; + } +@@ -579,11 +581,9 @@ parse_req_done: + /* special cases */ + if ((strcasecmp(dn, bindDN) != 0) && + (strcasecmp(ipa_changepw_principal_dn, bindDN) != 0)) { +- int i; +- + pwdata.changetype = IPA_CHANGETYPE_ADMIN; + +- for (i = 0; i < krbcfg->num_passsync_mgrs; i++) { ++ for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) { + if (strcasecmp(krbcfg->passsync_mgrs[i], bindDN) == 0) { + pwdata.changetype = IPA_CHANGETYPE_DSMGR; + break; +@@ -606,6 +606,8 @@ parse_req_done: + errMesg = ipapwd_error2string(ret); + ret = ipapwd_to_ldap_pwpolicy_error(ret); + slapi_pwpolicy_make_response_control(pb, -1, -1, ret); ++ LOG_PWDPOLICY("Failed to set password credentials for" ++ " '%s': %s\n", dn, errMesg); + rc = LDAP_CONSTRAINT_VIOLATION; + goto free_and_return; + } +@@ -666,7 +668,7 @@ free_and_return: + if (targetEntry) slapi_entry_free(targetEntry); + if (ber) ber_free(ber, 1); + +- LOG("%s", errMesg ? errMesg : "success"); ++ LOG("%s\n", errMesg ? errMesg : "success"); + slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL); + + return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; +@@ -732,7 +734,8 @@ static Slapi_Entry *get_entry_by_principal(const char *principal) + "krbCanonicalName", + "enrolledBy", NULL }; + Slapi_Entry **es = NULL; +- int res, ret, i; ++ int res, ret; ++ size_t i; + Slapi_Entry *entry = NULL; + + /* Find ancestor base DN */ +@@ -774,7 +777,7 @@ static Slapi_Entry *get_entry_by_principal(const char *principal) + + /* if there is none or more than one, freak out */ + if (i != 1) { +- LOG_TRACE("Too many entries, or entry no found (%d)", i); ++ LOG_TRACE("Too many entries, or entry no found (%ld)\n", i); + goto free_and_return; + } + entry = slapi_entry_dup(es[0]); +@@ -809,7 +812,7 @@ static bool is_allowed_to_access_attr(Slapi_PBlock *pb, char *bindDN, + */ + be = get_realm_backend(); + if (!be) { +- LOG_FATAL("Could not fetch REALM backend!"); ++ LOG_FATAL("Could not fetch REALM backend!\n"); + return false; + } + if (slapi_pblock_set(pb, SLAPI_BACKEND, be)) { +@@ -868,7 +871,8 @@ static void remove_user_password(Slapi_Mods *smods, + if ((NULL != pw) && (NULL == krbLastPwdChange)) { + slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, + "userPassword", NULL); +- LOG_TRACE("Removing userPassword from host entry\n"); ++ LOG_TRACE("Removing userPassword from host entry '%s'\n", ++ slapi_entry_get_dn_const(targetEntry)); + } + } + if (krbLastPwdChange) slapi_ch_free_string(&krbLastPwdChange); +@@ -891,8 +895,9 @@ static int store_new_keys(Slapi_Entry *target, char *svcname, char *bind_dn, + rc = set_krbLastPwdChange(smods, time_now); + if (rc) { + rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to set krbLastPwdChange"); +- err_msg = "Internal error while storing keytab data\n"; ++ LOG_FATAL("Failed to set krbLastPwdChange for target '%s'\n", ++ slapi_entry_get_dn_const(target)); ++ err_msg = "Internal error while storing keytab data"; + goto done; + } + +@@ -905,8 +910,9 @@ static int store_new_keys(Slapi_Entry *target, char *svcname, char *bind_dn, + rc = ipapwd_apply_mods(slapi_entry_get_dn_const(target), smods); + if (rc != LDAP_SUCCESS) { + rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to apply mods"); +- err_msg = "Internal error while saving keys\n"; ++ LOG_FATAL("Failed to apply mods to target '%s'\n", ++ slapi_entry_get_dn_const(target)); ++ err_msg = "Internal error while saving keys"; + goto done; + } + +@@ -914,8 +920,9 @@ static int store_new_keys(Slapi_Entry *target, char *svcname, char *bind_dn, + svcname, time_now); + if (rc != LDAP_SUCCESS) { + rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to set extradata"); +- err_msg = "Internal error while saving keytab extradata\n"; ++ LOG_FATAL("Failed to set extradata for target '%s'\n", ++ slapi_entry_get_dn_const(target)); ++ err_msg = "Internal error while saving keytab extradata"; + goto done; + } + +@@ -1003,7 +1010,7 @@ static int decode_setkeytab_request(krb5_context krbctx, + kset->mkvno = mkvno; + + rtag = ber_peek_tag(ber, &tlen); +- for (int i = 0; rtag == LBER_SEQUENCE; i++) { ++ for (size_t i = 0; rtag == LBER_SEQUENCE; i++) { + krb5_key_data *newset; + ber_tag_t ctag; + ber_int_t type; +@@ -1181,29 +1188,29 @@ static int encode_setkeytab_reply(struct ipapwd_keyset *kset, + rc = ber_printf(ber, "{i{", (ber_int_t)kset->keys[0].key_data_kvno); + if (rc == -1) { + rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to ber_printf the kvno"); ++ LOG_FATAL("Failed to ber_printf the kvno\n"); + goto done; + } + +- for (int i = 0; i < kset->num_keys; i++) { ++ for (size_t i = 0; i < kset->num_keys; i++) { + rc = ber_printf(ber, "{i}", (ber_int_t)kset->keys[i].key_data_type[0]); + if (rc == -1) { + rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to ber_printf the enctype"); ++ LOG_FATAL("Failed to ber_printf the enctype\n"); + goto done; + } + } + rc = ber_printf(ber, "}}"); + if (rc == -1) { + rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to ber_printf the termination"); ++ LOG_FATAL("Failed to ber_printf the termination\n"); + goto done; + } + + rc = ber_flatten(ber, &bvp); + if (rc == -1) { + rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to ber_flatten the buffer"); ++ LOG_FATAL("Failed to ber_flatten the buffer\n"); + goto done; + } + +@@ -1306,7 +1313,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + + /* get next kvno for entry (will be 1 if this is new) and fix keyset */ + kvno = ipapwd_get_cur_kvno(targetEntry) + 1; +- for (int i = 0; i < kset->num_keys; i++) { ++ for (size_t i = 0; i < kset->num_keys; i++) { + kset->keys[i].key_data_kvno = kvno; + } + +@@ -1352,7 +1359,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + + rc = encode_setkeytab_reply(kset, &bvp); + if (rc) { +- errMesg = "Internal Error.\n"; ++ errMesg = "Internal Error."; + goto free_and_return; + } + +@@ -1372,7 +1379,7 @@ free_and_return: + if (targetEntry) slapi_entry_free(targetEntry); + + if (svals) { +- for (int i = 0; svals[i]; i++) { ++ for (size_t i = 0; svals[i]; i++) { + slapi_value_free(&svals[i]); + } + free(svals); +@@ -1382,7 +1389,7 @@ free_and_return: + + if (rc == LDAP_SUCCESS) + errMesg = NULL; +- LOG("%s", errMesg ? errMesg : "success"); ++ LOG("%s\n", errMesg ? errMesg : "success"); + slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL); + + return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; +@@ -1403,7 +1410,6 @@ static int decode_getkeytab_request(struct berval *extop, bool *wantold, + krb5_key_salt_tuple *enctypes = NULL; + bool newkt; + bool ret; +- int i; + + ret = ipaasn1_dec_getkt(extop->bv_val, extop->bv_len, &newkt, + &svcname, &password, &etypes, &numtypes); +@@ -1423,7 +1429,7 @@ static int decode_getkeytab_request(struct berval *extop, bool *wantold, + goto done; + } + +- for (i = 0; i < numtypes; i++) { ++ for (size_t i = 0; i < numtypes; i++) { + enctypes[i].ks_enctype = etypes[i]; + enctypes[i].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; + } +@@ -1466,7 +1472,7 @@ static int encode_getkeytab_reply(krb5_context krbctx, + /* uses last key kvno */ + kvno = keys[num_keys-1].key_data_kvno; + +- for (int i = 0; i < num_keys; i++) { ++ for (size_t i = 0; i < num_keys; i++) { + krb5_enc_data cipher = { 0 }; + krb5_data plain = { 0 }; + krb5_int16 plen; +@@ -1516,7 +1522,7 @@ static int encode_getkeytab_reply(krb5_context krbctx, + rc = LDAP_SUCCESS; + + done: +- for (int i = 0; i < ksc.nkeys; i ++) { ++ for (size_t i = 0; i < ksc.nkeys; i++) { + free(ksc.ksdata[i].key.contents); + } + if (rc != LDAP_SUCCESS) { +@@ -1632,7 +1638,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + * this operation. */ + if (bind_dn == NULL || *bind_dn == '\0') { + /* Refuse the operation because they're bound anonymously */ +- err_msg = "Anonymous Binds are not allowed.\n"; ++ err_msg = "Anonymous Binds are not allowed."; + rc = LDAP_INSUFFICIENT_ACCESS; + goto free_and_return; + } +@@ -1648,7 +1654,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value); + if (!extop_value) { + LOG_FATAL("Failed to retrieve extended op value from pblock\n"); +- err_msg = "Failed to retrieve extended operation value\n"; ++ err_msg = "Failed to retrieve extended operation value"; + rc = LDAP_OPERATIONS_ERROR; + goto free_and_return; + } +@@ -1674,7 +1680,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + /* get Entry by krbPrincipalName */ + target_entry = get_entry_by_principal(service_name); + if (!target_entry) { +- err_msg = "PrincipalName not found.\n"; ++ err_msg = "PrincipalName not found."; + rc = LDAP_NO_SUCH_OBJECT; + goto free_and_return; + } +@@ -1690,7 +1696,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + if (!acl_ok) { + LOG_FATAL("Not allowed to retrieve keytab on [%s] as user [%s]!\n", + service_name, bind_dn); +- err_msg = "Insufficient access rights\n"; ++ err_msg = "Insufficient access rights"; + rc = LDAP_INSUFFICIENT_ACCESS; + goto free_and_return; + } +@@ -1701,6 +1707,8 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + /* if password was passed-in, check its length */ + rc = ipapwd_check_max_pwd_len(strlen(password), &err_msg); + if (rc) { ++ LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n", ++ bind_dn, err_msg); + goto free_and_return; + } + } +@@ -1712,7 +1720,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + if (!acl_ok) { + LOG_FATAL("Not allowed to set keytab on [%s]!\n", + service_name); +- err_msg = "Insufficient access rights\n"; ++ err_msg = "Insufficient access rights"; + rc = LDAP_INSUFFICIENT_ACCESS; + goto free_and_return; + } +@@ -1745,7 +1753,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + if (!svals) { + rc = LDAP_OPERATIONS_ERROR; + LOG_FATAL("encrypt_encode_keys failed!\n"); +- err_msg = "Internal error while encrypting keys\n"; ++ err_msg = "Internal error while encrypting keys"; + goto free_and_return; + } + +@@ -1765,7 +1773,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + rc = encode_getkeytab_reply(krbctx, krbcfg->kmkey, mkvno, + keys, num_keys, &bvp); + if (rc != LDAP_SUCCESS) { +- err_msg = "Internal Error.\n"; ++ err_msg = "Internal Error."; + goto free_and_return; + } + +@@ -1776,7 +1784,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + + free_and_return: + if (rc == LDAP_SUCCESS) err_msg = NULL; +- LOG("%s", err_msg ? err_msg : "success"); ++ LOG("%s\n", err_msg ? err_msg : "success"); + slapi_send_ldap_result(pb, rc, NULL, err_msg, 0, NULL); + + /* Free anything that we allocated above */ +@@ -1787,7 +1795,7 @@ free_and_return: + if (target_entry) slapi_entry_free(target_entry); + if (keys) ipa_krb5_free_key_data(keys, num_keys); + if (svals) { +- for (int i = 0; svals[i]; i++) { ++ for (size_t i = 0; svals[i]; i++) { + slapi_value_free(&svals[i]); + } + free(svals); +@@ -2031,7 +2039,7 @@ int ipapwd_init( Slapi_PBlock *pb ) + "ipapwd_post_init_betxn", ipapwd_post_init_betxn, + "IPA pwd post ops betxn", NULL, + ipapwd_plugin_id); +- } ++ } + + slapi_register_plugin("preoperation", 1, + "ipapwd_pre_init", ipapwd_pre_init, +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +index 45626523ffa1030cdff4f3e0ccdfa1618a51ccaf..6898e6596e1cbbb2cc69ba592401619ce86899d8 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +@@ -33,7 +33,7 @@ + * Authors: + * Simo Sorce + * +- * Copyright (C) 2007-2010 Red Hat, Inc. ++ * Copyright (C) 2007-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -248,6 +248,13 @@ static int ipapwd_pre_add(Slapi_PBlock *pb) + return 0; + } + ++ /* Get target DN */ ++ ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); ++ if (ret) { ++ rc = LDAP_OPERATIONS_ERROR; ++ goto done; ++ } ++ + /* Ok this is interesting, + * Check this is a clear text password, or refuse operation */ + if ('{' == userpw[0]) { +@@ -280,6 +287,8 @@ static int ipapwd_pre_add(Slapi_PBlock *pb) + } else { + rc = ipapwd_check_max_pwd_len(strlen(userpw_clear), &errMesg); + if (rc) { ++ LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n", ++ slapi_sdn_get_dn(sdn), errMesg); + goto done; + } + userpw = slapi_ch_strdup(userpw_clear); +@@ -329,13 +338,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb) + goto done; + } + +- /* Get target DN */ +- ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); +- if (ret) { +- rc = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- + /* time to get the operation handler */ + ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op); + if (ret != 0) { +@@ -359,7 +361,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb) + pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR; + } else { + char *binddn; +- int i; + + pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN; + +@@ -367,7 +368,7 @@ static int ipapwd_pre_add(Slapi_PBlock *pb) + slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn); + + /* if it is a passsync manager we also need to skip resets */ +- for (i = 0; i < krbcfg->num_passsync_mgrs; i++) { ++ for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) { + if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) { + pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR; + break; +@@ -385,6 +386,8 @@ static int ipapwd_pre_add(Slapi_PBlock *pb) + if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) && + (ret != 0) ) { + errMesg = ipapwd_error2string(ret); ++ LOG_PWDPOLICY("Failed to add password credentials for '%s': %s\n", ++ slapi_sdn_get_dn(sdn), errMesg); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } +@@ -507,6 +510,13 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + goto done; + } + ++ /* Get target DN */ ++ ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); ++ if (ret) { ++ rc = LDAP_OPERATIONS_ERROR; ++ goto done; ++ } ++ + /* grab the mods - we'll put them back later with + * our modifications appended + */ +@@ -568,6 +578,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + + rc = ipapwd_check_max_pwd_len(bv->bv_len, &errMesg); + if (rc) { ++ LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n", ++ slapi_sdn_get_dn(sdn), errMesg); + goto done; + } + slapi_ch_free_string(&unhashedpw); +@@ -591,14 +603,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + + /* OK we have something interesting here, start checking for + * pre-requisites */ +- +- /* Get target DN */ +- ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); +- if (ret) { +- rc = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- + tmp_sdn = slapi_sdn_dup(sdn); + if (tmp_sdn) { + /* xxxPAR: Ideally SLAPI_MODIFY_EXISTING_ENTRY should be +@@ -795,6 +799,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + const char *userpw_clear = &userpw[strlen("{CLEAR}")]; + rc = ipapwd_check_max_pwd_len(strlen(userpw_clear), &errMesg); + if (rc) { ++ LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n", ++ slapi_sdn_get_dn(sdn), errMesg); + goto done; + } + unhashedpw = slapi_ch_strdup(userpw_clear); +@@ -806,9 +812,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + slapi_ch_free_string(&userpw); + + } else if (slapi_is_encoded(userpw)) { +- +- LOG("Pre-Encoded passwords are not valid\n"); +- errMesg = "Pre-Encoded passwords are not valid\n"; ++ errMesg = "Pre-Encoded passwords are not valid"; ++ LOG("%s (%s)\n", errMesg, slapi_sdn_get_dn(sdn)); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } +@@ -843,7 +848,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + } else { + char *binddn; + Slapi_DN *bdn, *tdn; +- int i; + + /* Check Bind DN */ + slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn); +@@ -857,18 +861,16 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN; + + /* if it is a passsync manager we also need to skip resets */ +- for (i = 0; i < krbcfg->num_passsync_mgrs; i++) { ++ for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) { + if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) { + pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR; + break; + } + } +- + } + + slapi_sdn_free(&bdn); + slapi_sdn_free(&tdn); +- + } + + pwdop->pwdata.dn = slapi_ch_strdup(slapi_sdn_get_dn(sdn)); +@@ -884,6 +886,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) && + (ret != 0)) { + errMesg = ipapwd_error2string(ret); ++ LOG_PWDPOLICY("Check Password Policy failed for (%s) - %s/n", ++ pwdop->pwdata.dn, errMesg); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } +@@ -976,7 +980,6 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods, + int num_keys; + int mkvno; + int ret; +- int i; + + ret = slapi_entry_attr_find(entry, "ipaNTHash", &attr); + if (ret == 0) { +@@ -1008,7 +1011,7 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods, + + ret = LDAP_UNWILLING_TO_PERFORM; + +- for (i = 0; i < num_keys; i++) { ++ for (size_t i = 0; i < num_keys; i++) { + char nthash[16]; + krb5_enc_data cipher; + krb5_data plain; +@@ -1511,6 +1514,8 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) + } else { + rc = ipapwd_check_max_pwd_len(credentials->bv_len, &errMesg); + if (rc) { ++ LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n", ++ slapi_sdn_get_dn(sdn), errMesg); + goto invalid_creds; + } + } +-- +2.43.0 + diff --git a/SOURCES/0022-ipatests-fix-test_topology.patch b/SOURCES/0022-ipatests-fix-test_topology.patch deleted file mode 100644 index 92729ef..0000000 --- a/SOURCES/0022-ipatests-fix-test_topology.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 1278e614dd93bf0ac3d6e0c36cb9c277808afb2c Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Fri, 11 Aug 2023 08:01:18 +0200 -Subject: [PATCH] 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 ---- - ipatests/test_integration/test_topology.py | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/ipatests/test_integration/test_topology.py b/ipatests/test_integration/test_topology.py -index 8a240fa3c081a05b8f4501fe48694e01086003a1..618c9d5dcce994cd0359a291b044eb2cf0bddc74 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 --- -2.41.0 - diff --git a/SOURCES/0023-Issue-9497-update-debug-logging-in-ipa_uuid.patch b/SOURCES/0023-Issue-9497-update-debug-logging-in-ipa_uuid.patch new file mode 100644 index 0000000..660c715 --- /dev/null +++ b/SOURCES/0023-Issue-9497-update-debug-logging-in-ipa_uuid.patch @@ -0,0 +1,47 @@ +From a2fcfb9e17c4e7f2b4c57fa1eccdfe27d0c085d3 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 Dec 2023 08:41:43 -0500 +Subject: [PATCH] Issue 9497 - update debug logging in ipa_uuid + +Fixes: https://pagure.io/freeipa/issue/9497 + +Signed-off-by: Mark Reynolds +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c b/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c +index 87d8be2d88d9ff9bbf7d47eab57b765063f7a230..2fa84f5167341667050e3cfd4bda4c4a4991d06d 100644 +--- a/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c ++++ b/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c +@@ -30,7 +30,7 @@ + * Program may make changes or additions to the list of Approved + * Interfaces. + * +- * Copyright (C) 2010 Red Hat, Inc. ++ * Copyright (C) 2010-2023 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +@@ -1185,7 +1185,7 @@ static int ipauuid_pre_op(Slapi_PBlock *pb, int modtype) + * enforce is enabled. */ + errstr = slapi_ch_smprintf("Only the Directory Manager " + "can set arbitrary values " +- "for %s\n", cfgentry->attr); ++ "for %s", cfgentry->attr); + ret = LDAP_INSUFFICIENT_ACCESS; + goto done; + } +@@ -1221,7 +1221,7 @@ done: + } + + if (ret) { +- LOG("operation failure [%d]\n", ret); ++ LOG("operation failure [%d] - %s\n", ret, errstr); + slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL); + slapi_ch_free((void **)&errstr); + ret = EFAIL; +-- +2.43.0 + diff --git a/SOURCES/0023-ipatests-idm-api-related-tests.patch b/SOURCES/0023-ipatests-idm-api-related-tests.patch deleted file mode 100644 index 34c072a..0000000 --- a/SOURCES/0023-ipatests-idm-api-related-tests.patch +++ /dev/null @@ -1,560 +0,0 @@ -From ac6a2172f5dcb46701148c7b096ffa1b44076816 Mon Sep 17 00:00:00 2001 -From: Sudhir Menon -Date: Thu, 27 Jul 2023 14:33:08 +0530 -Subject: [PATCH] ipatests: idm api related tests. - -IDM API related tests are automated in the -above PR -Ref: https://freeipa.readthedocs.io/en/latest/api/basic_usage.html - -Signed-off-by: Sudhir Menon -Reviewed-By: Alexander Bokovoy -Reviewed-By: Florence Blanc-Renaud ---- - ipatests/test_integration/test_idm_api.py | 534 ++++++++++++++++++++++ - 1 file changed, 534 insertions(+) - create mode 100644 ipatests/test_integration/test_idm_api.py - -diff --git a/ipatests/test_integration/test_idm_api.py b/ipatests/test_integration/test_idm_api.py -new file mode 100644 -index 0000000000000000000000000000000000000000..eafef5dd8526bc14725d6bc32819cb5c7387f868 ---- /dev/null -+++ b/ipatests/test_integration/test_idm_api.py -@@ -0,0 +1,534 @@ -+# -+# Copyright (C) 2018 FreeIPA Contributors see COPYING for license -+# -+from __future__ import absolute_import -+ -+from ipatests.test_integration.base import IntegrationTest -+import textwrap -+ -+API_INIT = """ -+ from ipalib import api, errors -+ api.bootstrap_with_global_options(context="server") -+ api.finalize() -+ api.Backend.ldap2.connect() -+ """ -+ -+CERT = ( -+ b"MIIEkDCCAvigAwIBAgIBCzANBgkqhkiG9w0BAQsFADA5MRcwFQYDVQQKD\n" -+ b"A5URVNUUkVBTE0uVEVTVDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG\n" -+ b"9yaXR5MB4XDTIzMDcyODE3MTIxOVoXDTI1MDcyODE3MTIxOVowKjEXMBU\n" -+ b"GA1UECgwOVEVTVFJFQUxNLlRFU1QxDzANBgNVBAMMBmpzbWl0aDCCASIw\n" -+ b"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOF0XFrdVXmKp95AVZW5o\n" -+ b"BWcij6vJPqeU3UpzTLbM+fROhNaKMX9S+yXrJHifOmhCOuNA8TtptKVJx\n" -+ b"CIDZ1/5KwPBk4vrnwOBtVMCftHj87MabBqV/nmQQrCiKTcJu4aQEDI9Qh\n" -+ b"yza09EJKvG8KkpnyuShtkP2LgkUxIqkjBg4DLV7grO+I+aG17QTuQxUTy\n" -+ b"icfYDBnzD4hTKPLf7d9KNyG+sEeyN0gceLFMUYaQ4lyapcSzYJwOSAc2B\n" -+ b"EU73tLaJlQORHL7HmhxrjD1IgZyxFjp/ofLVZFFoJAqjz2FWzOxmQw+bc\n" -+ b"0WTzQjeSTGx+l3htj7MmhIRBMqr3Um6zXkLKMCAwEAAaOCATAwggEsMB8\n" -+ b"GA1UdIwQYMBaAFCIXu6QtsiBVo1yZQZ7MMHTl5Wj6MEAGCCsGAQUFBwEB\n" -+ b"BDQwMjAwBggrBgEFBQcwAYYkaHR0cDovL2lwYS1jYS50ZXN0cmVhbG0ud\n" -+ b"GVzdC9jYS9vY3NwMA4GA1UdDwEB/wQEAwIE8DAdBgNVHSUEFjAUBggrBg\n" -+ b"EFBQcDAQYIKwYBBQUHAwIweQYDVR0fBHIwcDBuoDagNIYyaHR0cDovL2l\n" -+ b"wYS1jYS50ZXN0cmVhbG0udGVzdC9pcGEvY3JsL01hc3RlckNSTC5iaW6i\n" -+ b"NKQyMDAxDjAMBgNVBAoMBWlwYWNhMR4wHAYDVQQDDBVDZXJ0aWZpY2F0Z\n" -+ b"SBBdXRob3JpdHkwHQYDVR0OBBYEFNwQNQAG8MsKQPwMFyGzRiMzRAa5MA\n" -+ b"0GCSqGSIb3DQEBCwUAA4IBgQB2g0mS8XAPI+aRBa5q7Vbp1245CvMP0Eq\n" -+ b"Cz6gvCNwtxW0UDKnB++d/YQ13ft+x9Xj3rB/M2YXxdxTpQnQQv34CUcyh\n" -+ b"PQKJthAsbKBpdusCGrbS54zKFR0MjxwOwIIDHuI6eu2AoSpsmYs5UGzQm\n" -+ b"oCfQhbImK7iGLy0rOHaON1cWAFmC6lzJ2TFELc4N3eLYGVZy2ZtyZTgA3\n" -+ b"l97rBCwbDDFF1JWoOByIq8Ij99ksyMXws++sNUpo/1l8Jt0Gn6RBiidZB\n" -+ b"ef4+kJN+t6RAAwRQ / 3cmEggXcFoV13KZ70PeMXeX6CKMwXIwt3q7A78\n" -+ b"Wc/0OIBREZLhXpkmogCzWCuatdzeBIhMhx0vDEzaxlhf32ZWfN5pFMpgq\n" -+ b"wLZsdwMf6J65kGbE5Pg3Yxk7OiByxZJnR8UlvbU3r6RhMWutD6C0aqqNt\n" -+ b"o3us5gTmfRc8Mf1l/BUgDqkBKOTU8FHREGemG1HoklBym/Pbua0VMUA+s\n" -+ b"0nECR4LLM/o9PCJ2Y3QPBZy8Hg=\n" -+) -+ -+ -+class TestAPIScenario(IntegrationTest): -+ """ -+ Tests for IDM API scenarios -+ """ -+ -+ topology = "line" -+ -+ def create_and_run_script(self, filename, user_code_script): -+ self.master.put_file_contents(filename, user_code_script) -+ self.master.run_command(["python3", filename]) -+ self.master.run_command(["rm", filename]) -+ -+ def test_idm_user_add(self): -+ """ -+ This test checks that ipa user using api.Command["user_add"] -+ and then checks that user is displayed using -+ api.Command["user_show"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ api.Command["user_add"]("jsmith", givenname="John", sn="Smith", -+ ipauserauthtype="otp") -+ cmd = api.Command["user_show"]("jsmith", all=True)["result"] -+ assert 'otp' in cmd['ipauserauthtype'] -+ assert 'John Smith' in cmd['cn'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/user_add.py", user_code_script -+ ) -+ -+ def test_idm_user_find(self): -+ """ -+ This test checks that user is displayed -+ using api.Command["user_find"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["user_find"]("jsmith") -+ assert '1 user matched' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/user_find.py", user_code_script -+ ) -+ -+ def test_idm_user_mod(self): -+ """ -+ This test checks that user attribute is modified -+ using api.Command["user_mod"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["user_mod"]("jsmith", -+ mail="jsmith@example.org")["result"] -+ assert 'jsmith@example.org' in cmd['mail'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/user_mod.py", user_code_script -+ ) -+ -+ def test_disable_user(self): -+ """ -+ This test checks that user is disabled -+ using api.Command["user_disable"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["user_disable"]("jsmith") -+ assert 'Disabled user account "jsmith"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/disable_user.py", user_code_script -+ ) -+ -+ def test_enable_user(self): -+ """ -+ This test checks that user is enabled -+ using api.Command["user_enable"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["user_enable"]("jsmith") -+ assert 'Enabled user account "jsmith"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/enable_user.py", user_code_script -+ ) -+ -+ def test_create_ipa_group(self): -+ """ -+ This test checks that group is created -+ using api.Command["group_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["group_add"]("developers", gidnumber=500, -+ description="Developers") -+ assert 'Added group "developers"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/create_group.py", user_code_script -+ ) -+ -+ def test_show_ipa_group(self): -+ """ -+ This test checks that group is displayed -+ using api.Command["group_show"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["group_show"]("developers") -+ assert 'developers' in cmd['result']['cn'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/group_show.py", user_code_script -+ ) -+ -+ def test_ipa_group_mod(self): -+ """ -+ This test checks that group description is modified -+ using api.Command["group_mod"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["group_mod"]("developers", description='developer') -+ ["result"] -+ assert 'Modified group "developers"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/group_mod.py", user_code_script -+ ) -+ -+ def test_add_members_to_ipa_group(self): -+ """ -+ This test checks that member is added to group -+ using api.Command["group_add_member"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["group_add_member"]("developers", -+ user='jsmith')["result"] -+ assert 'jsmith' in cmd['member_user'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/create_group_members.py", user_code_script -+ ) -+ -+ def test_ipa_group_find(self): -+ """ -+ This test checks that group is displayed -+ using api.Command["group_find"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["group_find"]("developers") -+ assert '1 group matched' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/group_find.py", user_code_script -+ ) -+ -+ def test_remove_member_group(self): -+ """ -+ This test checks that group member is removed -+ using api.Command["group_remove_member"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["group_remove_member"]("developers", -+ user="jsmith") -+ assert 'member_user' not in cmd -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/remove_member_group.py", user_code_script -+ ) -+ -+ def test_add_permission(self): -+ """ -+ This test checks that permission is added -+ using api.Command["permission_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["permission_add"]("Create users", -+ ipapermright='add', type='user') -+ assert 'Added permission "Create users"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/add_perm.py", user_code_script -+ ) -+ -+ def test_create_hbac_rule(self): -+ """ -+ This test checks that hbac rule is added -+ using api.Command["hbacrule_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["hbacrule_add"]("sshd_rule") -+ assert 'Added HBAC rule "sshd_rule"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/add_hbac_rule.py", user_code_script -+ ) -+ -+ def test_add_hbac_service(self): -+ """ -+ This test checks that hbac service is added using -+ api.Command["hbacsvc_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["hbacsvc_add"]("chronyd") -+ assert 'Added HBAC service "chronyd"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/add_hbac_svc.py", user_code_script -+ ) -+ -+ def test_enable_hbac_rule(self): -+ """ -+ This test checks that hbac rule is enabled using -+ api.Command["hbacrule_enable"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["hbacrule_enable"]("sshd_rule") -+ assert 'Enabled HBAC rule "sshd_rule"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/enable_hbacrule.py", user_code_script -+ ) -+ -+ def test_create_sudo_rule(self): -+ """ -+ This test checks that sudo rule is created using -+ api.Command["sudorule_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["sudorule_add"]("timechange") -+ assert 'Added Sudo Rule "timechange"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/create_sudos.py", user_code_script -+ ) -+ -+ def test_add_user_certificate(self): -+ """ -+ This test checks user certificate is added using -+ api.Command["user_add_cert"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ msg = 'Added certificates to user "jsmith"' -+ cmd = api.Command["user_add_cert"]("jsmith", usercertificate={CERT}) -+ assert msg in cmd["summary"] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/add_cert.py", user_code_script -+ ) -+ -+ def test_remove_user_certificate(self): -+ """ -+ This test checks that user certificate is removed -+ using api.Command["user_remove_cert"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ msg = 'Removed certificates from user "jsmith"' -+ cmd = api.Command["user_remove_cert"]("jsmith", usercertificate={CERT}) -+ assert msg in cmd["summary"] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/remove_cert.py", user_code_script -+ ) -+ -+ def test_certmaprule_add(self): -+ """ -+ This test checks that certmap rule is added using -+ api.Command["certmaprule_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ msg = ('Added Certificate Identity Mapping Rule "testrule"') -+ cmd = api.Command["certmaprule_add"]("testrule") -+ assert msg in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/certmap_rule_add.py", user_code_script -+ ) -+ -+ def test_certmaprule_enable(self): -+ """ -+ This test checks that certmap rule is enabled -+ using api.Command["certmaprule_enable"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ msg = ('Enabled Certificate Identity Mapping Rule "testrule"') -+ cmd = api.Command["certmaprule_enable"]("testrule") -+ assert msg in cmd["summary"] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/certmap_rule_enable.py", user_code_script -+ ) -+ -+ def test_certmaprule_disable(self): -+ """ -+ This test checks that certmap rule is disabled using -+ api.Command["certmaprule_disable"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ msg = ('Disabled Certificate Identity Mapping Rule "testrule"') -+ cmd = api.Command["certmaprule_disable"]("testrule") -+ assert msg in cmd["summary"] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/certmap_rule_disable.py", user_code_script -+ ) -+ -+ def test_certmaprule_del(self): -+ """ -+ This test checks that certmap rule is deleted using -+ api.Command["certmaprule_del"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ msg = ('Deleted Certificate Identity Mapping Rule "testrule"') -+ cmd = api.Command["certmaprule_del"]("testrule") -+ assert msg in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/certmap_rule_del.py", user_code_script -+ ) -+ -+ def test_add_role(self): -+ """ -+ This test checks that role and privilege is added using -+ api.Command["role_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd1 = api.Command["role_add"]("junioradmin", -+ description="Junior admin") -+ assert 'Added role "junioradmin"' in cmd1["summary"] -+ cmd2 = api.Command.role_add_privilege("junioradmin", -+ privilege="Vault Administrators")["result"] -+ assert 'Vault Administrators' in cmd2["memberof_privilege"] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/add_role.py", user_code_script -+ ) -+ -+ def test_add_subid(self): -+ """ -+ This test checks that subid is added for IPA user -+ using api.Command["subid_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["subid_add"](ipaowner="jsmith") -+ assert 'Added subordinate id ' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/add_subid.py", user_code_script -+ ) -+ -+ def test_add_otptoken(self): -+ """ -+ This test checks that otp token is added for IPA user -+ using api.Command["otptoken_add"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["otptoken_add"]( -+ type='HOTP', description='testotp', -+ ipatokenotpalgorithm='sha512', ipatokenowner='jsmith', -+ ipatokenotpdigits='6') -+ assert 'Added OTP token' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/add_otptoken.py", user_code_script -+ ) -+ -+ def test_user_del(self): -+ """ -+ This test checks that user is deleted -+ using api.Command["user_del"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["user_del"]("jsmith") -+ assert 'Deleted user "jsmith"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/user_del.py", user_code_script -+ ) -+ -+ def test_remove_ipa_group(self): -+ """ -+ This test checks that group is removed -+ using api.Command["group_del"] -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ cmd = api.Command["group_del"]("developers") -+ assert 'Deleted group "developers"' in cmd['summary'] -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/show_group.py", user_code_script -+ ) -+ -+ def test_batch_command(self): -+ """ -+ This test checks that batch commands -+ can be run using api. -+ """ -+ user_code_script = textwrap.dedent( -+ f""" -+ {API_INIT} -+ batch_args = [] -+ for i in range(5): -+ user_id = "user%i" % i -+ args = [user_id] -+ kw = {{'givenname' : user_id, 'sn' : user_id}} -+ batch_args.append({{'method' : 'user_add', 'params' : [args, kw]}}) -+ api.Command["batch"](*batch_args) -+ """ -+ ) -+ self.create_and_run_script( -+ "/tmp/batch.py", user_code_script -+ ) --- -2.41.0 - diff --git a/SOURCES/0024-hbactest-was-not-collecting-or-returning-messages.patch b/SOURCES/0024-hbactest-was-not-collecting-or-returning-messages.patch new file mode 100644 index 0000000..c04ee23 --- /dev/null +++ b/SOURCES/0024-hbactest-was-not-collecting-or-returning-messages.patch @@ -0,0 +1,82 @@ +From 9e950f89bedeb83267369d60b4a83c77f89e71d6 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 27 Nov 2023 16:11:08 -0500 +Subject: [PATCH] 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 1b54530b236cf654bc8ece7ab4e329850f5a6815..e0f93b9c265a176cb872fcf2728dbb3a66a264d9 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 887a35b7e67b257a2e54d51990af953ff8fbb316..568c13174ba617f2742b8f42c11b36dbde549cc2 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 + diff --git a/SOURCES/0024-ipatests-fixture-can-produce-IndexError.patch b/SOURCES/0024-ipatests-fixture-can-produce-IndexError.patch deleted file mode 100644 index 83ce90c..0000000 --- a/SOURCES/0024-ipatests-fixture-can-produce-IndexError.patch +++ /dev/null @@ -1,45 +0,0 @@ -From f816b4d9e6ff7a47b0da1a368d2454add78af07c Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Fri, 11 Aug 2023 09:10:30 +0200 -Subject: [PATCH] ipatests: fixture can produce IndexError - -The fixture issue_and_expire_acme_cert returns a function -that fills the hosts array. If the function is not called in -the test (for instance because a test is skipped, as in -TestACMEPrune::test_prune_cert_search_size_limit), hosts = [] -and hosts[0] raises an IndexError. - -Fix the fixture to check first that hosts is not empty. - -Related: https://pagure.io/freeipa/issue/9348 - -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Mohammad Rizwan Yusuf ---- - ipatests/test_integration/test_acme.py | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py -index c7389732cd067d49541cd04ea6687a6b95b4669f..bc989a9a2a00b0ac68b9dcffd4ccea269314961b 100644 ---- a/ipatests/test_integration/test_acme.py -+++ b/ipatests/test_integration/test_acme.py -@@ -633,9 +633,13 @@ def issue_and_expire_acme_cert(): - tasks.move_date(host, 'start', '-90days-60minutes') - - # restart ipa services as date moved and wait to get things settle -- time.sleep(10) -- hosts[0].run_command(['ipactl', 'restart']) -- time.sleep(10) -+ # if the internal fixture was not called (for instance because the test -+ # was skipped), hosts = [] and hosts[0] would produce an IndexError -+ # exception. -+ if hosts: -+ time.sleep(10) -+ hosts[0].run_command(['ipactl', 'restart']) -+ time.sleep(10) - - - class TestACMERenew(IntegrationTest): --- -2.41.0 - diff --git a/SOURCES/0025-Installer-activate-nss-and-pam-services-in-sssd.conf.patch b/SOURCES/0025-Installer-activate-nss-and-pam-services-in-sssd.conf.patch deleted file mode 100644 index a6a0eb3..0000000 --- a/SOURCES/0025-Installer-activate-nss-and-pam-services-in-sssd.conf.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 4a62a21499a4884f0db55d01966a6ff532a4ed1e Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 14 Aug 2023 10:53:05 +0200 -Subject: [PATCH] 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 ---- - ipaclient/install/client.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py -index ef29a2c8a3f673860cb22e0e6953853fd96a8572..07d62a748f77e990a38e28e3675abb05eef0da8d 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(): --- -2.41.0 - diff --git a/SOURCES/0025-ipatests-Verify-that-hbactest-will-return-messages.patch b/SOURCES/0025-ipatests-Verify-that-hbactest-will-return-messages.patch new file mode 100644 index 0000000..9cd1660 --- /dev/null +++ b/SOURCES/0025-ipatests-Verify-that-hbactest-will-return-messages.patch @@ -0,0 +1,56 @@ +From e8810696a38b70af286a2a2aae464ba4294e1fb5 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 28 Nov 2023 13:35:13 -0500 +Subject: [PATCH] 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 73c4ce232066dd7e45bc9a636f9fd955d50d6818..e2e66c759ab4bd1ac3e6dd2ab380c6359fc90042 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/0026-ipa-kdb-add-better-detection-of-allowed-user-auth-ty.patch b/SOURCES/0026-ipa-kdb-add-better-detection-of-allowed-user-auth-ty.patch new file mode 100644 index 0000000..4f6c600 --- /dev/null +++ b/SOURCES/0026-ipa-kdb-add-better-detection-of-allowed-user-auth-ty.patch @@ -0,0 +1,126 @@ +From c90ba9478b663bd5bcac9bb3af4272ee1406816b Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 11:46:19 +0200 +Subject: [PATCH] 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 06d511c762006f6a1e6e7a0ec663bc059489cf64..dbb98dba6d6d273e86e39e8ca8b8877d13f4299b 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 + diff --git a/SOURCES/0027-ipa-kdb-when-applying-ticket-policy-do-not-deny-PKIN.patch b/SOURCES/0027-ipa-kdb-when-applying-ticket-policy-do-not-deny-PKIN.patch new file mode 100644 index 0000000..ef2ac93 --- /dev/null +++ b/SOURCES/0027-ipa-kdb-when-applying-ticket-policy-do-not-deny-PKIN.patch @@ -0,0 +1,41 @@ +From 1fb026105ef397612a504722b2bcac29fbc69676 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 11:54:04 +0200 +Subject: [PATCH] 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 436ee0e62665594062e7be37e5b7925f76e921a0..2802221c79fe63ab4bd33bfbe4859517f3d91ec5 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 + diff --git a/SOURCES/0028-ipa-kdb-clarify-user-auth-table-mapping-use-of-_AUTH.patch b/SOURCES/0028-ipa-kdb-clarify-user-auth-table-mapping-use-of-_AUTH.patch new file mode 100644 index 0000000..d56a1fd --- /dev/null +++ b/SOURCES/0028-ipa-kdb-clarify-user-auth-table-mapping-use-of-_AUTH.patch @@ -0,0 +1,31 @@ +From fab08337dac0eb6322dc5ebe730b2541f4bb6111 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 12:20:55 +0200 +Subject: [PATCH] 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 dbb98dba6d6d273e86e39e8ca8b8877d13f4299b..4e6cacf24e27b05538db2c95ab85400bb83e3d58 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 + diff --git a/SOURCES/0029-ipatests-make-sure-PKINIT-enrollment-works-with-a-st.patch b/SOURCES/0029-ipatests-make-sure-PKINIT-enrollment-works-with-a-st.patch new file mode 100644 index 0000000..bfbe6bb --- /dev/null +++ b/SOURCES/0029-ipatests-make-sure-PKINIT-enrollment-works-with-a-st.patch @@ -0,0 +1,71 @@ +From 02b17c8560a6aabb4be1109a3a794412f527c83c Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 24 Nov 2023 13:00:48 +0200 +Subject: [PATCH] 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 caa0e6a34dc7e50359a41314e419a0d5be0c3aa8..5c2e7af0231677d4653ea2f82fa3dffed711a10d 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/0030-Check-the-HTTP-Referer-header-on-all-requests.patch b/SOURCES/0030-Check-the-HTTP-Referer-header-on-all-requests.patch new file mode 100644 index 0000000..ce9cbc1 --- /dev/null +++ b/SOURCES/0030-Check-the-HTTP-Referer-header-on-all-requests.patch @@ -0,0 +1,121 @@ +From 2c52a7dfd26ac561786e72e4304acbf9585698b6 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 b7116469d73f9a8595dbb2d1a3f39abe851f4fc3..198fc9e7dbae281f797dcccf96d21d475ff31e8c 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. +@@ -898,6 +908,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: +@@ -950,6 +963,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: +@@ -968,6 +984,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', +@@ -1016,6 +1035,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'): +@@ -1148,6 +1170,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'): +@@ -1365,6 +1390,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.43.0 + diff --git a/SOURCES/0031-Integration-tests-for-verifying-Referer-header-in-th.patch b/SOURCES/0031-Integration-tests-for-verifying-Referer-header-in-th.patch new file mode 100644 index 0000000..068d77a --- /dev/null +++ b/SOURCES/0031-Integration-tests-for-verifying-Referer-header-in-th.patch @@ -0,0 +1,359 @@ +From 14720c7690bda2b538dfc1d742eb4eb152dfd8a2 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 6cd034a719690646ee9238a5c6061e791e1c6fb5..8924798fc93c14e45beaf232a958d22398f61954 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 c3a47ab265f08db11ddfee2182401ccba90cf8df..df38ddb3d9e74baf908372be0780fcefbb258a5d 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 0000000000000000000000000000000000000000..9425cb7977fbc87210bf91464e0257830a938baf +--- /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 0000000000000000000000000000000000000000..4eade8bbaf304c48bf71c16892858d899b43cf88 +--- /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 929c3e899c3317acf59f2030b069898f4b282abc..61af0c40d07b31ef9e8ce1f069b05b2088605231 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.43.0 + diff --git a/SOURCES/0032-ipatests-Skip-ds_encryption-tests-on-RHEL9-SUT.patch b/SOURCES/0032-ipatests-Skip-ds_encryption-tests-on-RHEL9-SUT.patch new file mode 100644 index 0000000..8e2efe5 --- /dev/null +++ b/SOURCES/0032-ipatests-Skip-ds_encryption-tests-on-RHEL9-SUT.patch @@ -0,0 +1,46 @@ +From 8bdfbe8d2b203c64444390985011b2372f3bc08e Mon Sep 17 00:00:00 2001 +From: Sudhir Menon +Date: Wed, 20 Dec 2023 18:42:25 +0530 +Subject: [PATCH] ipatests: Skip ds_encryption tests on RHEL9 SUT. + +test_ipahealthcheck_ds_encryption tests are failing +in RHEL9 SUT because in this test tls protocol version +is set to TLS1.0 using the below command, but its +reset to TLS1.2 causing the test to fail. + +'dsconf', 'slapd-TESTREALM-TEST', 'security', 'set', '--tls-protocol-min=TLS1.0' + +Hence the test is skipped to be run on RHEL9.0 SUT. + +Signed-off-by: Sudhir Menon +Reviewed-By: Florence Blanc-Renaud +--- + ipatests/test_integration/test_ipahealthcheck.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 785e9abbae3b807f100a3d875e0c0b23f868be83..40c84898894681d8daf386b522118a6a7f793227 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -158,7 +158,6 @@ TOMCAT_CONFIG_FILES = ( + paths.CA_CS_CFG_PATH, + ) + +- + def run_healthcheck(host, source=None, check=None, output_type="json", + failures_only=False, config=None): + """ +@@ -1262,6 +1261,10 @@ class TestIpaHealthCheck(IntegrationTest): + ) + self.master.run_command(cmd) + ++ @pytest.mark.skipif((osinfo.id == 'rhel' ++ and osinfo.version_number >= (9,0)), ++ reason=" TLS versions below 1.2 are not " ++ "supported anymore in RHEL9.0 and above.") + def test_ipahealthcheck_ds_encryption(self, modify_tls): + """ + This testcase modifies the default TLS version of +-- +2.43.0 + diff --git a/SOURCES/0033-ACME-Don-t-treat-pki-server-ca-config-show-failures-.patch b/SOURCES/0033-ACME-Don-t-treat-pki-server-ca-config-show-failures-.patch new file mode 100644 index 0000000..559ee5f --- /dev/null +++ b/SOURCES/0033-ACME-Don-t-treat-pki-server-ca-config-show-failures-.patch @@ -0,0 +1,61 @@ +From b465cf6ea596907a2845c38df9c2446efe8e65ae Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 4 Jan 2024 17:32:45 -0500 +Subject: [PATCH] ACME: Don't treat pki-server ca-config-show failures as fatal + +Up to PKI 11.5.0 even when a pki-server call failed it had a +return value of 0. This was fixed in 11.5.0 which breaks +ipa-acme-manage pruning. If a configuration value is not set +then the call fails and the tool gives up with an error like: + +ERROR: No such parameter: jobsScheduler.job.pruning.certRetentionUnit + +In previous versions this resulted in an empty string so the tool +displayed the default value. + +So now upon failure look in the stderr output for "No such parameter" +and return an empty string so the behavior is consistent between +both old and new PKI server versions. + +Fixes: https://pagure.io/freeipa/issue/9503 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/install/ipa_acme_manage.py | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/install/ipa_acme_manage.py b/ipaserver/install/ipa_acme_manage.py +index e7c35ff6fb5b7a30ac9e2c0c18f8db805cf06ee9..dc2359f49dfdd5c8f44ab96ee11a7240f8937e11 100644 +--- a/ipaserver/install/ipa_acme_manage.py ++++ b/ipaserver/install/ipa_acme_manage.py +@@ -261,8 +261,13 @@ class IPAACMEManage(AdminTool): + result = run(args, raiseonerr=False, capture_output=True, + capture_error=True) + if result.returncode != 0: ++ # See if the parameter doesn't exist. If not then no ++ # user-specified value has been set. ++ # ERROR: No such parameter: jobsScheduler... ++ if 'No such parameter' in result.error_output: ++ return '' + raise RuntimeError(result.error_output) +- return result ++ return result.output.strip() + + def ca_config_set(directive, value, + prefix='jobsScheduler.job.pruning'): +@@ -274,9 +279,8 @@ class IPAACMEManage(AdminTool): + raise RuntimeError('Updating %s failed' % directive) + + def ca_config_show(directive): +- result = run_pki_server('ca-config-show', directive, +- prefix='jobsScheduler.job.pruning') +- return result.output.strip() ++ return run_pki_server('ca-config-show', directive, ++ prefix='jobsScheduler.job.pruning') + + def config_show(): + status = ca_config_show('enabled') +-- +2.43.0 + diff --git a/SOURCES/0034-Fix-ipa-client-automount-install-uninstall-with-new-.patch b/SOURCES/0034-Fix-ipa-client-automount-install-uninstall-with-new-.patch new file mode 100644 index 0000000..891632c --- /dev/null +++ b/SOURCES/0034-Fix-ipa-client-automount-install-uninstall-with-new-.patch @@ -0,0 +1,125 @@ +From 6340e88341b09b06391b35e50e8c4d7619b12dab Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Fri, 1 Dec 2023 08:51:05 -0500 +Subject: [PATCH] Fix ipa-client-automount install/uninstall with new install + states + +Issue 8384 introduced a new installation state for the statestore +to identify when client/server installation is completely finished +rather than relying on has_files(). + +The problem is that ipa-client-automount may be called during +ipa-client-install and since installation is not complete at that +point the automount install was failing with "IPA client not +configured". + +Add a new state, 'automount', to designate that automount installation +is in process. If check_client_configuration() fails it checks to +see if [installation] automount is True. If so it continues with the +installation. + +This also addresses an issue where the filestore and statestore are +shared between the client and automount installers but the client +wasn't refreshing state after automount completed. This resulted in +an incomplete state and index file of backed-up files which caused +files to not be restored on uninstall and the state file to be +orphaned. + +Fixes: https://pagure.io/freeipa/issue/9487 + +Signed-off-by: Rob Crittenden +Reviewed-By: Christian Heimes +Reviewed-By: Florence Blanc-Renaud +--- + ipaclient/install/client.py | 14 ++++++++++++-- + ipaclient/install/ipa_client_automount.py | 14 ++++++++------ + 2 files changed, 20 insertions(+), 8 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 7e3adee351ae31ed9fcbba422fcc03a1f904e1f9..976d3821dd6d66b5b7653298c628a2bc267fa8c6 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -1273,7 +1273,7 @@ def create_sshd_ipa_config(options): + logger.info('Configured %s', paths.SSHD_IPA_CONFIG) + + +-def configure_automount(options): ++def configure_automount(options, statestore): + logger.info('\nConfiguring automount:') + + args = [ +@@ -1286,12 +1286,15 @@ def configure_automount(options): + if not options.sssd: + args.append('--no-sssd') + ++ statestore.backup_state('installation', 'automount', True) + try: + result = run(args) + except Exception as e: + logger.error('Automount configuration failed: %s', str(e)) + else: + logger.info('%s', result.output_log) ++ finally: ++ statestore.delete_state('installation', 'automount') + + + def configure_nisdomain(options, domain, statestore): +@@ -3305,7 +3308,11 @@ def _install(options, tdict): + configure_sshd_config(fstore, options) + + if options.location: +- configure_automount(options) ++ configure_automount(options, statestore) ++ ++ # Reload the state as automount install may have modified it ++ fstore._load() ++ statestore._load() + + if options.configure_firefox: + configure_firefox(options, statestore, cli_domain) +@@ -3368,12 +3375,15 @@ def uninstall(options): + fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) + statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) + ++ statestore.backup_state('installation', 'automount', True) + try: + run([paths.IPA_CLIENT_AUTOMOUNT, "--uninstall", "--debug"]) + except CalledProcessError as e: + if e.returncode != CLIENT_NOT_CONFIGURED: + logger.error( + "Unconfigured automount client failed: %s", str(e)) ++ finally: ++ statestore.delete_state('installation', 'automount') + + # Reload the state as automount unconfigure may have modified it + fstore._load() +diff --git a/ipaclient/install/ipa_client_automount.py b/ipaclient/install/ipa_client_automount.py +index b4b3387530afa9e80d13dd69e9d80080702f9e07..ee27872868b9ceaffdc58a9cf3fa89938e045526 100644 +--- a/ipaclient/install/ipa_client_automount.py ++++ b/ipaclient/install/ipa_client_automount.py +@@ -340,14 +340,16 @@ def configure_nfs(fstore, statestore, options): + + + def configure_automount(): +- try: +- check_client_configuration() +- except ScriptError as e: +- print(e.msg) +- sys.exit(e.rval) ++ statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) ++ if not statestore.get_state('installation', 'automount'): ++ # not called from ipa-client-install ++ try: ++ check_client_configuration() ++ except ScriptError as e: ++ print(e.msg) ++ sys.exit(e.rval) + + fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) +- statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) + + options, _args = parse_options() + +-- +2.43.0 + diff --git a/SOURCES/0035-ipatests-Test-client-install-uninstall-with-automoun.patch b/SOURCES/0035-ipatests-Test-client-install-uninstall-with-automoun.patch new file mode 100644 index 0000000..f275038 --- /dev/null +++ b/SOURCES/0035-ipatests-Test-client-install-uninstall-with-automoun.patch @@ -0,0 +1,73 @@ +From 18764964b72ba237eba5f7b1078185b2f0393d72 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Fri, 1 Dec 2023 10:47:24 -0500 +Subject: [PATCH] ipatests: Test client install/uninstall with automount + enabled + +The automount installation was failing. Confirm that it is fixed. + +The uninstall was not restoring all files/configuration. Verify +that the index and state files are gone which means that all state +and files were restored. + +Fixes: https://pagure.io/freeipa/issue/9487 + +Signed-off-by: Rob Crittenden +Reviewed-By: Christian Heimes +Reviewed-By: Florence Blanc-Renaud +--- + .../test_installation_client.py | 25 +++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/ipatests/test_integration/test_installation_client.py b/ipatests/test_integration/test_installation_client.py +index 56e1593bfcfa3eb7f9918fc6f2993d836884ea38..f8567b39eead4dffd522aad504fa72a086969257 100644 +--- a/ipatests/test_integration/test_installation_client.py ++++ b/ipatests/test_integration/test_installation_client.py +@@ -8,12 +8,14 @@ Module provides tests for various options of ipa-client-install. + + from __future__ import absolute_import + ++import os + import pytest + import re + import shlex + import textwrap + + from ipaplatform.paths import paths ++from ipalib.sysrestore import SYSRESTORE_STATEFILE, SYSRESTORE_INDEXFILE + from ipatests.test_integration.base import IntegrationTest + from ipatests.pytest_ipa.integration import tasks + from ipatests.pytest_ipa.integration.firewall import Firewall +@@ -90,6 +92,29 @@ class TestInstallClient(IntegrationTest): + assert 'includedir {dir}'.format( + dir=paths.SSSD_PUBCONF_KRB5_INCLUDE_D_DIR + ).encode() not in krb5_cfg ++ tasks.uninstall_client(self.clients[0]) ++ ++ def test_install_with_automount(self): ++ """Test that installation with automount is successful""" ++ tasks.install_client(self.master, self.clients[0], ++ extra_args=['--automount-location', 'default']) ++ ++ def test_uninstall_with_automount(self): ++ """Test that uninstall with automount is successful and complete""" ++ tasks.uninstall_client(self.clients[0]) ++ index = os.path.join( ++ paths.IPA_CLIENT_SYSRESTORE, SYSRESTORE_INDEXFILE ++ ) ++ state = os.path.join( ++ paths.IPA_CLIENT_SYSRESTORE, SYSRESTORE_STATEFILE ++ ) ++ for filepath in (index, state): ++ try: ++ self.clients[0].get_file_contents(filepath) ++ except IOError: ++ pass ++ else: ++ pytest.fail("The client file %s was not removed" % filepath) + + + class TestClientInstallBind(IntegrationTest): +-- +2.43.0 + diff --git a/SOURCES/0036-ipa-client-automount-Don-t-use-deprecated-ipadiscove.patch b/SOURCES/0036-ipa-client-automount-Don-t-use-deprecated-ipadiscove.patch new file mode 100644 index 0000000..1c93282 --- /dev/null +++ b/SOURCES/0036-ipa-client-automount-Don-t-use-deprecated-ipadiscove.patch @@ -0,0 +1,66 @@ +From 526147ec9362124191a54c9ae8debd0234af3d49 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Fri, 1 Dec 2023 09:08:48 -0500 +Subject: [PATCH] ipa-client-automount: Don't use deprecated + ipadiscovery.IPADiscovery + +This class was moved to ipaclient/discovery.py in e6d560af66 to make +it available to PyPI. + +Related: https://pagure.io/freeipa/issue/9487 + +Signed-off-by: Rob Crittenden +Reviewed-By: Christian Heimes +Reviewed-By: Florence Blanc-Renaud +--- + ipaclient/install/ipa_client_automount.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/ipaclient/install/ipa_client_automount.py b/ipaclient/install/ipa_client_automount.py +index ee27872868b9ceaffdc58a9cf3fa89938e045526..297a784c4e1b6f1d29d51b6d3fd4b91d05672b9c 100644 +--- a/ipaclient/install/ipa_client_automount.py ++++ b/ipaclient/install/ipa_client_automount.py +@@ -36,7 +36,7 @@ from six.moves.urllib.parse import urlsplit + + from optparse import OptionParser # pylint: disable=deprecated-module + from ipapython import ipachangeconf +-from ipaclient.install import ipadiscovery ++from ipaclient import discovery + from ipaclient.install.client import ( + CLIENT_NOT_CONFIGURED, + CLIENT_ALREADY_CONFIGURED, +@@ -384,12 +384,12 @@ def configure_automount(): + sys.exit(CLIENT_ALREADY_CONFIGURED) + + autodiscover = False +- ds = ipadiscovery.IPADiscovery() ++ ds = discovery.IPADiscovery() + if not options.server: + print("Searching for IPA server...") + ret = ds.search(ca_cert_path=ca_cert_path) + logger.debug('Executing DNS discovery') +- if ret == ipadiscovery.NO_LDAP_SERVER: ++ if ret == discovery.NO_LDAP_SERVER: + logger.debug('Autodiscovery did not find LDAP server') + s = urlsplit(api.env.xmlrpc_uri) + server = [s.netloc] +@@ -409,14 +409,14 @@ def configure_automount(): + server = options.server + logger.debug("Verifying that %s is an IPA server", server) + ldapret = ds.ipacheckldap(server, api.env.realm, ca_cert_path) +- if ldapret[0] == ipadiscovery.NO_ACCESS_TO_LDAP: ++ if ldapret[0] == discovery.NO_ACCESS_TO_LDAP: + print("Anonymous access to the LDAP server is disabled.") + print("Proceeding without strict verification.") + print( + "Note: This is not an error if anonymous access has been " + "explicitly restricted." + ) +- elif ldapret[0] == ipadiscovery.NO_TLS_LDAP: ++ elif ldapret[0] == discovery.NO_TLS_LDAP: + logger.warning("Unencrypted access to LDAP is not supported.") + elif ldapret[0] != 0: + sys.exit('Unable to confirm that %s is an IPA server' % server) +-- +2.43.0 + diff --git a/SOURCES/0037-Server-affinity-Retain-user-requested-remote-server.patch b/SOURCES/0037-Server-affinity-Retain-user-requested-remote-server.patch new file mode 100644 index 0000000..66a939b --- /dev/null +++ b/SOURCES/0037-Server-affinity-Retain-user-requested-remote-server.patch @@ -0,0 +1,98 @@ +From d2ffa10df62bba45aa63232d3ad9a5ebf7158eea Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 5 Dec 2023 14:34:31 -0500 +Subject: [PATCH] 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 +--- + ipaserver/install/server/replicainstall.py | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 27fbdef8ec9aa5ae343352ebf3c61d74d65c8958..8096b6accb4c94fefdfcc06f19584c63c24d7baf 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 +-- +2.43.0 + diff --git a/SOURCES/0038-get_directive-don-t-error-out-on-substring-mismatch.patch b/SOURCES/0038-get_directive-don-t-error-out-on-substring-mismatch.patch new file mode 100644 index 0000000..1447e72 --- /dev/null +++ b/SOURCES/0038-get_directive-don-t-error-out-on-substring-mismatch.patch @@ -0,0 +1,120 @@ +From 95b066d629de935bfb52e732ce52026e18e9c64d Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Wed, 10 Jan 2024 16:45:12 -0500 +Subject: [PATCH] get_directive: don't error out on substring mismatch + +This function is designed to retrieve a value from an +ini-like file. In particular PKI CS.cfg. + +In an attempt to be more efficient a substring search, +using startswith(), is used before calling a regular +expression match. + +The problem is that if the requested directive is a +substring of a different one then it will pass the +startswith() and fail the regular expression match +with a ValueError, assuming it is malformed. + +There is no need for this. The caller must be able to +handle None as a response anyway. So continue if +no match is found. + +This was seen when PKI dropped storing certificate blobs +in CS.cfg. The CA certificate is stored in ca.signing.cert. +If it isn't present then ca.signing.certnickname will match +the substring but not the directive. This should not be +treated as an error. + +Fixes: https://pagure.io/freeipa/issue/9506 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipapython/directivesetter.py | 5 ++- + .../test_ipapython/test_directivesetter.py | 33 +++++++++++++++++++ + 2 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/ipapython/directivesetter.py b/ipapython/directivesetter.py +index f4e496c7f0f785a909bfb5b8196582fb5dd865ea..732e1c239ca375e6ec08882e4731f97cb1ff58a9 100644 +--- a/ipapython/directivesetter.py ++++ b/ipapython/directivesetter.py +@@ -182,6 +182,9 @@ def get_directive(filename, directive, separator=' '): + if separator == ' ': + separator = '[ \t]+' + ++ if directive is None: ++ return None ++ + result = None + with open(filename, "r") as fd: + for line in fd: +@@ -193,7 +196,7 @@ def get_directive(filename, directive, separator=' '): + if match: + value = match.group(1) + else: +- raise ValueError("Malformed directive: {}".format(line)) ++ continue + + result = unquote_directive_value(value.strip(), '"') + result = result.strip(' ') +diff --git a/ipatests/test_ipapython/test_directivesetter.py b/ipatests/test_ipapython/test_directivesetter.py +index 08a30124b12c3bd8edf8fa7930377faf7b181f5d..ff86559e0a3eb018e4a26a489c190a0da380ce1f 100644 +--- a/ipatests/test_ipapython/test_directivesetter.py ++++ b/ipatests/test_ipapython/test_directivesetter.py +@@ -18,6 +18,10 @@ WHITESPACE_CONFIG = [ + 'foobar\t2\n', + ] + ++SUBSTRING_CONFIG = [ ++ 'foobar=2\n', ++] ++ + + class test_set_directive_lines: + def test_remove_directive(self): +@@ -88,6 +92,7 @@ class test_set_directive: + + class test_get_directive: + def test_get_directive(self, tmpdir): ++ """Test retrieving known values from a config file""" + configfile = tmpdir.join('config') + configfile.write(''.join(EXAMPLE_CONFIG)) + +@@ -97,6 +102,34 @@ class test_get_directive: + assert '2' == directivesetter.get_directive(str(configfile), + 'foobar', + separator='=') ++ assert None is directivesetter.get_directive(str(configfile), ++ 'notfound', ++ separator='=') ++ ++ def test_get_directive_substring(self, tmpdir): ++ """Test retrieving values from a config file where there is ++ a similar substring that is not present. ++ """ ++ configfile = tmpdir.join('config') ++ configfile.write(''.join(SUBSTRING_CONFIG)) ++ ++ assert None is directivesetter.get_directive(str(configfile), ++ 'foo', ++ separator='=') ++ assert '2' == directivesetter.get_directive(str(configfile), ++ 'foobar', ++ separator='=') ++ ++ def test_get_directive_none(self, tmpdir): ++ """Test retrieving a value from a config file where the ++ directive is None. i.e. don't fail. ++ """ ++ configfile = tmpdir.join('config') ++ configfile.write(''.join(EXAMPLE_CONFIG)) ++ ++ assert None is directivesetter.get_directive(str(configfile), ++ None, ++ separator='=') + + + class test_get_directive_whitespace: +-- +2.43.0 + diff --git a/SOURCES/0039-host-update-System-Manage-Host-Keytab-permission.patch b/SOURCES/0039-host-update-System-Manage-Host-Keytab-permission.patch new file mode 100644 index 0000000..a4c46a9 --- /dev/null +++ b/SOURCES/0039-host-update-System-Manage-Host-Keytab-permission.patch @@ -0,0 +1,101 @@ +From 3842116185de6ae8714f30b57bd75c7eddde53d8 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 21 Dec 2023 09:38:57 +0200 +Subject: [PATCH] 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 +--- + ACI.txt | 2 +- + ipaserver/plugins/host.py | 3 ++- + ipatests/test_integration/test_user_permissions.py | 7 +++++++ + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/ACI.txt b/ACI.txt +index e6d6e3d1586c098f528d17fe940a1364b415654f..236bb43677bd9d84798a7ab418412b337fbf5c59 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 3ef510edc77a07ad504f07614d0c5524a3c34646..b02c8b55fde037c5fa0a9c73575b22e3c7177806 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 3333a4f6b961961aea7dadf2eb36d7ed3b31e410..cd1096ff3582f9c0cfdb16b5ed876164139f1a1b 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 +-- +2.43.0 + diff --git a/SOURCES/0040-adtrustinstance-make-sure-NetBIOS-name-defaults-are-.patch b/SOURCES/0040-adtrustinstance-make-sure-NetBIOS-name-defaults-are-.patch new file mode 100644 index 0000000..fbd49d7 --- /dev/null +++ b/SOURCES/0040-adtrustinstance-make-sure-NetBIOS-name-defaults-are-.patch @@ -0,0 +1,35 @@ +From eab52d3cda9bbec716008c040551bd11facd0e11 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 17 Jan 2024 12:27:26 +0200 +Subject: [PATCH] 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 +--- + ipaserver/install/adtrustinstance.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index d55ba849157bee8e335e2e0772514fc15ec11193..2ff68dfb46371a6118eb67515347eb762a37e1ec 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" % \ +-- +2.43.0 + diff --git a/SOURCES/0041-Server-affinity-Don-t-rely-just-on-ca-kra-_enabled-f.patch b/SOURCES/0041-Server-affinity-Don-t-rely-just-on-ca-kra-_enabled-f.patch new file mode 100644 index 0000000..e6aed29 --- /dev/null +++ b/SOURCES/0041-Server-affinity-Don-t-rely-just-on-ca-kra-_enabled-f.patch @@ -0,0 +1,54 @@ +From 851ce93ac07044172a7db56d54ab9e1d7c7ec79f Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 15 Jan 2024 09:05:58 -0500 +Subject: [PATCH] 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 +--- + ipaserver/install/server/replicainstall.py | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 8096b6accb4c94fefdfcc06f19584c63c24d7baf..191913ddb973b94bcd8ad920570edcee27349ffd 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") +-- +2.43.0 + diff --git a/SOURCES/0042-ipatests-wait-for-replica-update-in-test_dns_locatio.patch b/SOURCES/0042-ipatests-wait-for-replica-update-in-test_dns_locatio.patch new file mode 100644 index 0000000..61926ae --- /dev/null +++ b/SOURCES/0042-ipatests-wait-for-replica-update-in-test_dns_locatio.patch @@ -0,0 +1,42 @@ +From 3b2f3d41e4de0bcb78bfaecb32e06cbd22b809c2 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 +--- + 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 44900af8015ff62728f64bc626eedfcead41e214..89a310892954cbee88d1cf38683e80a2e47122ef 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/0043-Server-affinity-call-ca.install-if-there-is-a-CA-in-.patch b/SOURCES/0043-Server-affinity-call-ca.install-if-there-is-a-CA-in-.patch new file mode 100644 index 0000000..2d463e6 --- /dev/null +++ b/SOURCES/0043-Server-affinity-call-ca.install-if-there-is-a-CA-in-.patch @@ -0,0 +1,69 @@ +From 5dbb3101cee7a96ec8eef40be8e802d456c0d06c Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 22 Jan 2024 08:36:27 -0500 +Subject: [PATCH] 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 +--- + ipaserver/install/ca.py | 7 ++++--- + ipaserver/install/server/replicainstall.py | 7 +++++-- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py +index c93ae1fce4c8848d493677eafee7952740e51631..187f8032b6190799027135d5d3932dbdee4dea8a 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 191913ddb973b94bcd8ad920570edcee27349ffd..b3fd27e6a15db298f9a97d514d24662c83141013 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1382,11 +1382,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 +@@ -1398,7 +1400,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") +-- +2.43.0 + diff --git a/SOURCES/0044-ipapython-Clean-up-krb5_error.patch b/SOURCES/0044-ipapython-Clean-up-krb5_error.patch new file mode 100644 index 0000000..a022956 --- /dev/null +++ b/SOURCES/0044-ipapython-Clean-up-krb5_error.patch @@ -0,0 +1,144 @@ +From 33638de180a8157e369ad6c61f9e3406d9e85404 Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Tue, 23 Jan 2024 19:12:53 +0300 +Subject: [PATCH] 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 +--- + ipapython/session_storage.py | 25 ++++++++++++------------- + 1 file changed, 12 insertions(+), 13 deletions(-) + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index c43ef7d4e8ef5931f6d74d360be131fe46159dc7..371cf152472d54c9a59b60bece9559323ede78b7 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 +-- +2.43.0 + diff --git a/SOURCES/0045-ipapython-Correct-return-type-of-krb5_free_cred_cont.patch b/SOURCES/0045-ipapython-Correct-return-type-of-krb5_free_cred_cont.patch new file mode 100644 index 0000000..ed6743d --- /dev/null +++ b/SOURCES/0045-ipapython-Correct-return-type-of-krb5_free_cred_cont.patch @@ -0,0 +1,47 @@ +From f8a616dc6196324145372713da772fe9b2352e53 Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Tue, 23 Jan 2024 19:19:43 +0300 +Subject: [PATCH] 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 +--- + ipapython/session_storage.py | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index 371cf152472d54c9a59b60bece9559323ede78b7..dc36f54939a838bcb933dfb0089410d9b00f9e4d 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, +-- +2.43.0 + diff --git a/SOURCES/0046-ipapython-Propagate-KRB5Error-exceptions-on-iteratin.patch b/SOURCES/0046-ipapython-Propagate-KRB5Error-exceptions-on-iteratin.patch new file mode 100644 index 0000000..1043528 --- /dev/null +++ b/SOURCES/0046-ipapython-Propagate-KRB5Error-exceptions-on-iteratin.patch @@ -0,0 +1,53 @@ +From 59b8a9fb7169561c7ba9168fe84f47ae94e5ce23 Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Tue, 23 Jan 2024 19:52:34 +0300 +Subject: [PATCH] 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 +--- + ipapython/session_storage.py | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index dc36f54939a838bcb933dfb0089410d9b00f9e4d..e890dc9b11475cc26d212ccbe040df3cfbfba6e8 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)) + +-- +2.43.0 + diff --git a/SOURCES/0047-ipa-kdb-Fix-memory-leak-during-PAC-verification.patch b/SOURCES/0047-ipa-kdb-Fix-memory-leak-during-PAC-verification.patch new file mode 100644 index 0000000..71bfd51 --- /dev/null +++ b/SOURCES/0047-ipa-kdb-Fix-memory-leak-during-PAC-verification.patch @@ -0,0 +1,91 @@ +From 34b58d8ee93ab385c1f3ba1166377fc1008a9c17 Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Wed, 24 Jan 2024 15:50:17 +0100 +Subject: [PATCH] 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 +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 1558e2bead288d9d00014e9b3b059934e80b54e4..2866304e1e374fb6a8dc3400dd1f56583d9d9197 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 || +@@ -2398,32 +2405,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; + } +@@ -2470,6 +2466,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; +-- +2.43.0 + diff --git a/SOURCES/0048-sidgen-ignore-staged-users-when-generating-SIDs.patch b/SOURCES/0048-sidgen-ignore-staged-users-when-generating-SIDs.patch new file mode 100644 index 0000000..9621b29 --- /dev/null +++ b/SOURCES/0048-sidgen-ignore-staged-users-when-generating-SIDs.patch @@ -0,0 +1,83 @@ +From 37dfe80132d665b1fced67540457362c3ee00a7b 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 0feff7eec9999a76bf950b8b9fc9fa25b3a2fa88..bd46982d06b3272874f256a8b0c2293fa4829f5b 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 6f784804cd39acdf88ceceb0e21b272a04fa13fc..cb763ebf8c733e50483c23856a248eb536c796f1 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 + diff --git a/SOURCES/0049-sidgen-fix-missing-prototypes.patch b/SOURCES/0049-sidgen-fix-missing-prototypes.patch new file mode 100644 index 0000000..4430148 --- /dev/null +++ b/SOURCES/0049-sidgen-fix-missing-prototypes.patch @@ -0,0 +1,26 @@ +From a1f42f0258d9e84928a112e4c39419aad0cebb3b 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 bd46982d06b3272874f256a8b0c2293fa4829f5b..aec862796a8364de84e26fbca96a270a8fb508fc 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/0050-kdb-PAC-generator-do-not-fail-if-canonical-principal.patch b/SOURCES/0050-kdb-PAC-generator-do-not-fail-if-canonical-principal.patch new file mode 100644 index 0000000..415ae95 --- /dev/null +++ b/SOURCES/0050-kdb-PAC-generator-do-not-fail-if-canonical-principal.patch @@ -0,0 +1,48 @@ +From d09acb5869c5d0faa35b8784c1fea1c1be3f014f Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 26 Jan 2024 20:53:39 +0200 +Subject: [PATCH] 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 +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 2866304e1e374fb6a8dc3400dd1f56583d9d9197..16374a59468975ebaea5ce18ac6445ec577e5e6a 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); +-- +2.43.0 + diff --git a/SOURCES/0051-ipatests-Skip-tests-for-ipahealtcheck-tests-for-spec.patch b/SOURCES/0051-ipatests-Skip-tests-for-ipahealtcheck-tests-for-spec.patch new file mode 100644 index 0000000..85ae84f --- /dev/null +++ b/SOURCES/0051-ipatests-Skip-tests-for-ipahealtcheck-tests-for-spec.patch @@ -0,0 +1,65 @@ +From 8c1f56dbab5de1c06fc424f3c58d366274d70688 Mon Sep 17 00:00:00 2001 +From: Sudhir Menon +Date: Mon, 29 Jan 2024 22:07:43 +0530 +Subject: [PATCH] ipatests: Skip tests for ipahealtcheck tests for specific pki + version + +CADogtagCertsConfigCheck is no more available on RHEL9, hence the +respective tests are skipped. + +Check 'CADogtagCertsConfigCheck' not found in Source 'pki.server.healthcheck.meta.csconfig' + +Ref: https://issues.redhat.com/browse/RHEL-21367 + +Signed-off-by: Sudhir Menon +Reviewed-By: Florence Blanc-Renaud +--- + .../test_integration/test_ipahealthcheck.py | 23 +++++++++++++++---- + 1 file changed, 18 insertions(+), 5 deletions(-) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index 28200e0961a23996935c7b1c2b76f2b4b127e066..7323b073273bd95d7b62d19fd5afe03edb2a21da 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -507,6 +507,11 @@ class TestIpaHealthCheck(IntegrationTest): + Testcase checks behaviour of check DogtagCertsConfigCheck in + ipahealthcheck.dogtag.ca when tomcat config file is removed + """ ++ version = tasks.get_pki_version(self.master) ++ if version >= parse_version("11.5"): ++ pytest.skip("Skipping test for 11.5 pki version, since the " ++ "check CADogtagCertsConfigCheck itself is skipped " ++ "See ipa-healthcheck ticket 317") + returncode, data = run_healthcheck( + self.master, + "ipahealthcheck.dogtag.ca", +@@ -1453,13 +1458,21 @@ class TestIpaHealthCheck(IntegrationTest): + This testcase checks that CADogtagCertsConfigCheck can handle + cert renewal, when there can be two certs with the same nickname + """ +- if (tasks.get_pki_version(self.master) < tasks.parse_version('11.4.0')): ++ if (tasks.get_pki_version( ++ self.master) < tasks.parse_version('11.4.0')): + raise pytest.skip("PKI known issue #2022561") +- self.master.run_command(['ipa-cacert-manage', 'renew', '--self-signed']) ++ elif (tasks.get_pki_version( ++ self.master) >= tasks.parse_version('11.5.0')): ++ raise pytest.skip("Skipping test for 11.5 pki version, since " ++ "check CADogtagCertsConfigCheck is " ++ "not present in source " ++ "pki.server.healthcheck.meta.csconfig") ++ self.master.run_command( ++ ['ipa-cacert-manage', 'renew', '--self-signed'] ++ ) + returncode, data = run_healthcheck( +- self.master, +- "pki.server.healthcheck.meta.csconfig", +- "CADogtagCertsConfigCheck", ++ self.master, "pki.server.healthcheck.meta.csconfig", ++ "CADogtagCertsConfigCheck" + ) + assert returncode == 0 + for check in data: +-- +2.43.0 + diff --git a/SOURCES/0052-ipatests-remove-xfail-thanks-to-sssd-2.9.4.patch b/SOURCES/0052-ipatests-remove-xfail-thanks-to-sssd-2.9.4.patch new file mode 100644 index 0000000..d65cf4e --- /dev/null +++ b/SOURCES/0052-ipatests-remove-xfail-thanks-to-sssd-2.9.4.patch @@ -0,0 +1,42 @@ +From b00fd308831428400b96442290ec7bc90bde348f Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 30 Jan 2024 10:43:00 +0100 +Subject: [PATCH] ipatests: remove xfail thanks to sssd 2.9.4 + +SSSD 2.9.4 fixes some issues related to auto-private-group + +Related: https://pagure.io/freeipa/issue/9295 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Anuja More +--- + ipatests/test_integration/test_trust.py | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py +index 12f000c1ad1cbce2710900b0e364a501ed6b8e52..3b9f0fbd51f11ff2c97fed50f7bb61a67326b183 100644 +--- a/ipatests/test_integration/test_trust.py ++++ b/ipatests/test_integration/test_trust.py +@@ -1155,7 +1155,8 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust): + ): + self.mod_idrange_auto_private_group(type) + sssd_version = tasks.get_sssd_version(self.clients[0]) +- bad_version = sssd_version >= tasks.parse_version("2.8.2") ++ bad_version = (tasks.parse_version("2.8.2") <= sssd_version ++ < tasks.parse_version("2.9.4")) + cond = (type == 'hybrid') and bad_version + with xfail_context(condition=cond, + reason="https://pagure.io/freeipa/issue/9295"): +@@ -1237,7 +1238,9 @@ class TestPosixAutoPrivateGroup(BaseTestTrust): + self.mod_idrange_auto_private_group(type) + if type == "true": + sssd_version = tasks.get_sssd_version(self.clients[0]) +- with xfail_context(sssd_version >= tasks.parse_version("2.8.2"), ++ bad_version = (tasks.parse_version("2.8.2") <= sssd_version ++ < tasks.parse_version("2.9.4")) ++ with xfail_context(bad_version, + "https://pagure.io/freeipa/issue/9295"): + (uid, gid) = self.get_user_id(self.clients[0], posixuser) + assert uid == gid +-- +2.43.0 + diff --git a/SOURCES/0053-ipatests-add-xfail-for-autoprivate-group-test-with-o.patch b/SOURCES/0053-ipatests-add-xfail-for-autoprivate-group-test-with-o.patch new file mode 100644 index 0000000..b94ed43 --- /dev/null +++ b/SOURCES/0053-ipatests-add-xfail-for-autoprivate-group-test-with-o.patch @@ -0,0 +1,52 @@ +From ed2a8eb0cefadfe0544074114facfef381349ae0 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 9 Feb 2024 10:42:59 +0100 +Subject: [PATCH] ipatests: add xfail for autoprivate group test with override + +Because of SSSD issue 7169, secondary groups are not +retrieved when autoprivate group is set and an idoverride +replaces the user's primary group. +Mark the known issues as xfail. + +Related: https://github.com/SSSD/sssd/issues/7169 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Anuja More +--- + ipatests/test_integration/test_trust.py | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py +index 3b9f0fbd51f11ff2c97fed50f7bb61a67326b183..2b945140dbc477f8bcd0d3b26513000d2006fa82 100644 +--- a/ipatests/test_integration/test_trust.py ++++ b/ipatests/test_integration/test_trust.py +@@ -1164,8 +1164,12 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust): + assert (uid == self.uid_override and gid == self.gid_override) + test_group = self.clients[0].run_command( + ["id", nonposixuser]).stdout_text +- with xfail_context(type == "hybrid", +- 'https://github.com/SSSD/sssd/issues/5989'): ++ cond2 = ((type == 'false' ++ and sssd_version >= tasks.parse_version("2.9.4")) ++ or type == 'hybrid') ++ with xfail_context(cond2, ++ 'https://github.com/SSSD/sssd/issues/5989 ' ++ 'and 7169'): + assert "domain users@{0}".format(self.ad_domain) in test_group + + @pytest.mark.parametrize('type', ['hybrid', 'true', "false"]) +@@ -1287,5 +1291,9 @@ class TestPosixAutoPrivateGroup(BaseTestTrust): + assert(uid == self.uid_override + and gid == self.gid_override) + result = self.clients[0].run_command(['id', posixuser]) +- assert "10047(testgroup@{0})".format( +- self.ad_domain) in result.stdout_text ++ sssd_version = tasks.get_sssd_version(self.clients[0]) ++ bad_version = sssd_version >= tasks.parse_version("2.9.4") ++ with xfail_context(bad_version and type in ('false', 'hybrid'), ++ "https://github.com/SSSD/sssd/issues/7169"): ++ assert "10047(testgroup@{0})".format( ++ self.ad_domain) in result.stdout_text +-- +2.43.0 + diff --git a/SOURCES/0054-ipatests-fix-tasks.wait_for_replication-method.patch b/SOURCES/0054-ipatests-fix-tasks.wait_for_replication-method.patch new file mode 100644 index 0000000..663ce37 --- /dev/null +++ b/SOURCES/0054-ipatests-fix-tasks.wait_for_replication-method.patch @@ -0,0 +1,36 @@ +From 7f1142504d41a821357168acd2484c7cb7c1a4c2 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 13 Feb 2024 13:30:15 +0100 +Subject: [PATCH] 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 +--- + ipatests/pytest_ipa/integration/tasks.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py +index ee6dec7a1d2416b442a6ce20e41b09d84f43b5c7..418c63f2c17e4fc0a2f625bca9a02879c1a1566f 100755 +--- a/ipatests/pytest_ipa/integration/tasks.py ++++ b/ipatests/pytest_ipa/integration/tasks.py +@@ -1520,7 +1520,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: +-- +2.43.0 + diff --git a/SOURCES/0055-ipa-kdb-Rework-ipadb_reinit_mspac.patch b/SOURCES/0055-ipa-kdb-Rework-ipadb_reinit_mspac.patch new file mode 100644 index 0000000..55abf54 --- /dev/null +++ b/SOURCES/0055-ipa-kdb-Rework-ipadb_reinit_mspac.patch @@ -0,0 +1,707 @@ +From febfd9c64d748a435a9d0756d4710898a0e2aa49 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 +--- + daemons/ipa-kdb/ipa_kdb.c | 14 +- + daemons/ipa-kdb/ipa_kdb.h | 4 +- + daemons/ipa-kdb/ipa_kdb_mspac.c | 342 +++++++++++++----------- + 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, 219 insertions(+), 170 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index 4e6cacf24e27b05538db2c95ab85400bb83e3d58..903e19e83bbe383b878a3b9261dd501f96058d51 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -449,6 +449,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; + +@@ -528,16 +529,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 59484d8bb69236a4ef59aeefdf9658a71c8cd520..8459ab8e0bb76c8da5c18101b0521bea86e8aecc 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -371,7 +371,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 16374a59468975ebaea5ce18ac6445ec577e5e6a..b0eb3324bf4b7d8eeb7b332c39de4023784f6337 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) { +@@ -2634,7 +2637,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; + +@@ -2789,7 +2792,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) { +@@ -2874,7 +2878,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++); + +@@ -2989,108 +2993,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; ++ } ++ ++ 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; ++ } + } + } + +- /* 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; +- } +- +- 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 */ +@@ -3098,53 +3108,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, +@@ -3154,11 +3192,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; + } + +@@ -3220,7 +3258,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 7f0ca7a7966ff159828f81283f8d067476abc594..e650cfa73c558c53b28f75de26d83132e8c4b234 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 faf47ad1b9b979a9acb8020eff5d663124b250ac..96cd50e4c8afe141880dd7e2e9472623cef667d8 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 3badd5b088b3f017546d5df3cecbf7427fedd59d..60db048e1f328c3a31b58d2a3b17d9cac615467c 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 139f091aa9f920af14a9ba91f4d83151e23a6a20..16a15748fb94ff31d91aa656532a7b40fa4f195a 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -1598,6 +1598,7 @@ static krb5_error_code dbget_alias(krb5_context kcontext, + -1, + }; + size_t i = 0; ++ const char *stmsg = NULL; + + /* For TGS-REQ server principal lookup, KDC asks with KRB5_KDB_FLAG_REFERRAL_OK + * and client usually asks for an KRB5_NT_PRINCIPAL type principal. */ +@@ -1685,8 +1686,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/0056-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch b/SOURCES/0056-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch new file mode 100644 index 0000000..992df1f --- /dev/null +++ b/SOURCES/0056-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch @@ -0,0 +1,126 @@ +From b1390d1ad7e94256148a6b26431ff1e97fb8b7b3 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 +--- + 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 bdd988ad186c1d773b454608e63c585c332af22a..a29bd6e5f437d9d07f2d995d7bc884e7f2419c27 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 + ) + ) +@@ -703,14 +703,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' +@@ -721,7 +746,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 + +@@ -731,15 +756,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/0057-Vault-improve-vault-server-archival-retrieval-calls-.patch b/SOURCES/0057-Vault-improve-vault-server-archival-retrieval-calls-.patch new file mode 100644 index 0000000..a5bd8af --- /dev/null +++ b/SOURCES/0057-Vault-improve-vault-server-archival-retrieval-calls-.patch @@ -0,0 +1,87 @@ +From c6f79e0453c9d417173ca7ecfbd5e233c6a89a9f 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 +--- + 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 a47cf7bd306154b24fd6dc0223718faf55440489..0bcc2a1ce4bb5f61b3a69fd0cc8d2b4516e20b63 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 +@@ -1096,16 +1097,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], +@@ -1176,11 +1182,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/0058-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch b/SOURCES/0058-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch new file mode 100644 index 0000000..85515f8 --- /dev/null +++ b/SOURCES/0058-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch @@ -0,0 +1,97 @@ +From 601de6985ce0efdd701bfd8361cea72c4b87f39b 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 +--- + 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 62e0729d1b6332fce142cd1d85ccc461539d06ae..44cda15920176c9eebb9a3d16f089210ff17dcdd 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 7fdf2e0ed0f3ed99a6672f527d38dda0ce5ef8bb..e0aa129ad3b0114afc4d1eae7f1ed76bb41276ae 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 d0636a56c3d2c09a5c83c08cc1fc12768212ac3e..0fd148697dadd59ad87eb401528761010a1555de 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -284,6 +284,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 f42faea049c720c931ce7ea865e3c35acbc08b5d..31d4f8398cfb0251cc59ada909eb55635b83e960 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1794,6 +1794,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/0059-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch b/SOURCES/0059-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch new file mode 100644 index 0000000..91131ed --- /dev/null +++ b/SOURCES/0059-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch @@ -0,0 +1,28 @@ +From ac44c3d0a69aa2b3f8230c3ab13dca5ab5a78dd0 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 +--- + 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 b0eb3324bf4b7d8eeb7b332c39de4023784f6337..9723103d8a77294ed7457d9b48bfc0d98b9ccef1 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -3087,6 +3087,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.10.2.tar.gz.asc b/SOURCES/freeipa-4.10.2.tar.gz.asc deleted file mode 100644 index da2e960..0000000 --- a/SOURCES/freeipa-4.10.2.tar.gz.asc +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmR+6S4ACgkQaYdvcqbi -008kvQ/9HuW6rWRJPY9/bqfaaeTKAT9JPCdq6jwDj7rSxpzJRE2r8vuwL3XxvXEa -8qW3qwx4qcBV3hrOPX3annilCgfyUN0ayF72rfDxGmVzTifooEVd0mmaDJOd9JHy -wLVYbImvsitC59luFF/XTIx5Xgo8Msu7BtAC5Tf5+mws0/i6ZxmyufYBPEmydgVM -jdpVSZfq4hd4HwfYH0Ej5c8sWfv2OTTENyBWn5x9LiWvC6rJi42u7ubcnWoCi6If -kXzJCRf7JTDzDvmMDVZMoTJCQa0EwlST7Yr9V7rLJViUGDwqxVO7VoeQi2WoV5PN -zDSoLoCVEgLdDt0EAYRlBxPzoe65kNBdGFhC3eT0uIO676NZuTMVEXaRtId1wfnU -o52xx3r5OPvRrjRLhKsAsMSiqX0Cr/wgH1L8QuSpriM1gMO6jZTkFpGtjD1XEvWd -VsiSVqR0y+E8U3bkLOTHvByPvWk9QlmN0e6WDyV0FvGPaPlD2VCGNLqraldeEKvr -wQxVvMWMqX+CKs2ZWYlzfgzFd0ZlUfsYhTcDaliJIh5Tcn5Ow+CSX/vWMXS6Msyh -80fS5k7NswIsa3bA0QSoFpAcSkNxxovKyIWpXamL/MgX/nqZqJE74aUtchANl9jd -j5yAU2s4eUuvbTMQkQjEJHl97a/jjGCGKnCunF/RO3WLaGdi9Dk= -=Bq0h ------END PGP SIGNATURE----- diff --git a/SOURCES/freeipa-4.11.0.tar.gz.asc b/SOURCES/freeipa-4.11.0.tar.gz.asc new file mode 100644 index 0000000..6806376 --- /dev/null +++ b/SOURCES/freeipa-4.11.0.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmUcDfoACgkQaYdvcqbi +00+tSA/8DjMUZ1P21qxTpPzybT6tx54X1wzAK+mSB+pC2gSLcv932lVERUvNmTC6 +vXtTiI2xWlkcw0VQdtmN0ncdPYuFsC9EeClnWXSH3ayDXP/EguF9uWZDO6zsK4yP +pLVgJKvCX1O5EUN+l9pKtPAnyphSEkcd5rWqzEmfQV6+mILdVS3W8BVOuq8oY4xq +J/1HmbV6b78rrsH9CW9TjFVKlNsOYKTS2dDCYSbidjE69hsvdS8yD8eH9WgVPR2z +X2zidVLIRv7D9Ayy59+rfEfuehhG2FD4lL54DWqUqlw87prN7a1aH7jgs6o+1XCK +2pBDcC6oac+mtCTAGNaMnormzbR55RLgYKpwoyv/OvspuRzsHDfgQy91+YvIBqFV +EW0oB5TG4GeDn3jUPPyehtpRm+TUTeCQiBTcbeksEYDol4xxePKqIC3X313zm/fc +IKYQ2XwZTyrxGOtVmvAncHzwkyVgyDA6aJNApxsu0EdcpFBm/qhuAeadxrLR1v4+ +j90yAaUlKduviX5XE1XGCHqvwHXttLmB1npxPmzSPe6MYlmzXRcen8SFPK/dquyC +Vi+CykIR1jelqBvHObIbU4Q8ss0irQhSbHGpHxkup1cmO2b/YILzVrOkE3TIUbps +g1zb4lryzWkXU1q8qPHsS3Fh1HEfuZCWk6Eg6xmmhxENdAsTCeo= +=iHBW +-----END PGP SIGNATURE----- diff --git a/SPECS/freeipa.spec b/SPECS/freeipa.spec index 1c0672b..078c72d 100644 --- a/SPECS/freeipa.spec +++ b/SPECS/freeipa.spec @@ -87,8 +87,8 @@ %global httpd_version 2.4.37-21 %global bind_version 9.11.20-6 -# Fix for https://github.com/SSSD/sssd/issues/6331 -%global sssd_version 2.8.0 +# support for passkey +%global sssd_version 2.9.0 %else # Fedora @@ -148,8 +148,8 @@ # F35+, adds IdP integration %global sssd_version 2.7.0 %else -# Fix for https://github.com/SSSD/sssd/issues/6331 -%global sssd_version 2.8.0 +# Support for passkey +%global sssd_version 2.9.0 %endif # Fedora @@ -210,7 +210,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.10.2 +%define IPA_VERSION 4.11.0 # Release candidate version -- uncomment with one percent for RC versions #%%global rc_version %%nil %define AT_SIGN @ @@ -223,7 +223,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 4%{?rc_version:.%rc_version}%{?dist} +Release: 8%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPL-3.0-or-later @@ -247,31 +247,65 @@ Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch %endif %if 0%{?rhel} == 9 -Patch0001: 0001-webuitests-close-notification-which-hides-Add-button.patch -Patch0002: 0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch -Patch0003: 0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch -Patch0004: 0004-Revert-cert_find-fix-call-with-all.patch -Patch0005: 0005-Use-the-python-cryptography-parser-directly-in-cert-.patch -Patch0006: 0006-Upgrade-add-PKI-drop-in-file-if-missing.patch -Patch0007: 0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch -Patch0008: 0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch -Patch0009: 0009-Detection-of-PKI-subsystem.patch -Patch0010: 0010-Upgrade-fix-replica-agreement.patch -Patch0011: 0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch -Patch0012: 0012-tests-fix-backup-restore-scenario-with-replica.patch -Patch0013: 0013-OTP-fix-data-type-to-avoid-endianness-issue.patch -Patch0014: 0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch -Patch0015: 0015-User-plugin-improve-error-related-to-non-existing-id.patch -Patch0016: 0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch -Patch0017: 0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch -Patch0018: 0018-Prevent-the-admin-user-from-being-deleted.patch -Patch0019: 0019-ipa-kdb-fix-error-handling-of-is_master_host.patch -Patch0020: 0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch -Patch0021: 0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch -Patch0022: 0022-ipatests-fix-test_topology.patch -Patch0023: 0023-ipatests-idm-api-related-tests.patch -Patch0024: 0024-ipatests-fixture-can-produce-IndexError.patch -Patch0025: 0025-Installer-activate-nss-and-pam-services-in-sssd.conf.patch +Patch0001: 0001-ipatests-fix-healthcheck-test-without-DNS.patch +Patch0002: 0002-ipatests-fix-healthcheck-test-for-indent-option.patch +Patch0003: 0003-ipatests-fix-test_ipactl_scenario_check.patch +Patch0004: 0004-ipalib-fix-the-IPACertificate-validity-dates.patch +Patch0005: 0005-Allow-password-policy-minlength-to-be-removed-like-o.patch +Patch0006: 0006-ipatests-Skip-the-test-failing-due-to-FIPS-policy.patch +Patch0007: 0007-The-PKI-JSON-API-the-revocation-reason-key-may-be-ca.patch +Patch0008: 0008-WIP-Get-the-PKI-version-from-the-remote-to-determine.patch +Patch0009: 0009-ipatests-fix-expected-output-for-ipahealthcheck.meta.patch +Patch0010: 0010-ipatests-ignore-nsslapd-accesslog-logbuffering-WARN-.patch +Patch0011: 0011-ipatests-fix-expected-output-for-ipahealthcheck.ipa..patch +Patch0012: 0012-group-add-member-fails-with-an-external-member.patch +Patch0013: 0013-Handle-samba-changes-in-samba.security.dom_sid.patch +Patch0014: 0014-test_install-restart-services-after-date-change.patch +Patch0015: 0015-Issue-9497-Add-new-password-policy-logging-function.patch +Patch0016: 0016-Issue-9497-Update-logging-in-ipa_enrollment.patch +Patch0017: 0017-Issue-9497-update-debug-logging-in-ipa_graceperiod.patch +Patch0018: 0018-Issue-9497-update-debug-logging-in-ipa_lockout.patch +Patch0019: 0019-Issue-9497-update-debug-logging-in-ipa_modrdn.patch +Patch0020: 0020-Issue-9497-update-debug-logging-in-ipa_otp_counter.patch +Patch0021: 0021-Issue-9497-update-debug-logging-in-ipa_otp_lasttoken.patch +Patch0022: 0022-Issue-9497-update-debug-logging-in-ipa-pwd-extop.patch +Patch0023: 0023-Issue-9497-update-debug-logging-in-ipa_uuid.patch +Patch0024: 0024-hbactest-was-not-collecting-or-returning-messages.patch +Patch0025: 0025-ipatests-Verify-that-hbactest-will-return-messages.patch +Patch0026: 0026-ipa-kdb-add-better-detection-of-allowed-user-auth-ty.patch +Patch0027: 0027-ipa-kdb-when-applying-ticket-policy-do-not-deny-PKIN.patch +Patch0028: 0028-ipa-kdb-clarify-user-auth-table-mapping-use-of-_AUTH.patch +Patch0029: 0029-ipatests-make-sure-PKINIT-enrollment-works-with-a-st.patch +Patch0030: 0030-Check-the-HTTP-Referer-header-on-all-requests.patch +Patch0031: 0031-Integration-tests-for-verifying-Referer-header-in-th.patch +Patch0032: 0032-ipatests-Skip-ds_encryption-tests-on-RHEL9-SUT.patch +Patch0033: 0033-ACME-Don-t-treat-pki-server-ca-config-show-failures-.patch +Patch0034: 0034-Fix-ipa-client-automount-install-uninstall-with-new-.patch +Patch0035: 0035-ipatests-Test-client-install-uninstall-with-automoun.patch +Patch0036: 0036-ipa-client-automount-Don-t-use-deprecated-ipadiscove.patch +Patch0037: 0037-Server-affinity-Retain-user-requested-remote-server.patch +Patch0038: 0038-get_directive-don-t-error-out-on-substring-mismatch.patch +Patch0039: 0039-host-update-System-Manage-Host-Keytab-permission.patch +Patch0040: 0040-adtrustinstance-make-sure-NetBIOS-name-defaults-are-.patch +Patch0041: 0041-Server-affinity-Don-t-rely-just-on-ca-kra-_enabled-f.patch +Patch0042: 0042-ipatests-wait-for-replica-update-in-test_dns_locatio.patch +Patch0043: 0043-Server-affinity-call-ca.install-if-there-is-a-CA-in-.patch +Patch0044: 0044-ipapython-Clean-up-krb5_error.patch +Patch0045: 0045-ipapython-Correct-return-type-of-krb5_free_cred_cont.patch +Patch0046: 0046-ipapython-Propagate-KRB5Error-exceptions-on-iteratin.patch +Patch0047: 0047-ipa-kdb-Fix-memory-leak-during-PAC-verification.patch +Patch0048: 0048-sidgen-ignore-staged-users-when-generating-SIDs.patch +Patch0049: 0049-sidgen-fix-missing-prototypes.patch +Patch0050: 0050-kdb-PAC-generator-do-not-fail-if-canonical-principal.patch +Patch0051: 0051-ipatests-Skip-tests-for-ipahealtcheck-tests-for-spec.patch +Patch0052: 0052-ipatests-remove-xfail-thanks-to-sssd-2.9.4.patch +Patch0053: 0053-ipatests-add-xfail-for-autoprivate-group-test-with-o.patch +Patch0054: 0054-ipatests-fix-tasks.wait_for_replication-method.patch +Patch0055: 0055-ipa-kdb-Rework-ipadb_reinit_mspac.patch +Patch0056: 0056-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch +Patch0057: 0057-Vault-improve-vault-server-archival-retrieval-calls-.patch +Patch0058: 0058-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch +Patch0059: 0059-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -581,12 +615,8 @@ Requires: python3-pyasn1 >= 0.3.2-2 Requires: python3-sssdconfig >= %{sssd_version} Requires: python3-psutil Requires: rpm-libs -# Indirect dependency: use newer urllib3 with TLS 1.3 PHA support -%if 0%{?rhel} -Requires: python3-urllib3 >= 1.24.2-3 -%else -Requires: python3-urllib3 >= 1.25.7 -%endif +# For urllib3.util.ssl_match_hostname +Requires: python3-urllib3 >= 1.25.8 %description -n python3-ipaserver IPA is an integrated solution to provide centrally managed Identity (users, @@ -739,6 +769,9 @@ Recommends: libsss_sudo Recommends: sudo Requires: (libsss_sudo if sudo) +# Passkey support +Recommends: sssd-passkey + Provides: %{alt_name}-client = %{version} Conflicts: %{alt_name}-client Obsoletes: %{alt_name}-client < %{version} @@ -909,6 +942,8 @@ Requires: platform-python-setuptools %else Requires: python3-setuptools %endif +# For urllib3.util.ssl_match_hostname +Requires: python3-urllib3 >= 1.25.8 %description -n python3-ipalib IPA is an integrated solution to provide centrally managed Identity (users, @@ -1763,6 +1798,51 @@ fi %endif %changelog +* Tue Feb 20 2024 Florence Blanc-Renaud - 4.11.0-8 +- Resolves: RHEL-12143 'ipa vault-add is failing with ipa: ERROR: an internal error has occurred in FIPS mode +- Resolves: RHEL-25738 ipa-kdb: Cannot determine if PAC generator is available + +* Fri Feb 16 2024 Florence Blanc-Renaud - 4.11.0-7 +- Resolves: RHEL-25260 tier-1-upstream-dns-locations failed on RHEL8.8 gating +- Resolves: RHEL-25738 ipa-kdb: Cannot determine if PAC generator is available +- Resolves: RHEL-25815 Backport latest test fixes in python3-ipatests + +* Fri Feb 09 2024 2024 Florence Blanc-Renaud - 4.11.0-6 +- Resolves: RHEL-23627 IPA stops working if HTTP/... service principal was created before FreeIPA 4.4.0 and never modified +- Resolves: RHEL-23625 sidgen plugin does not ignore staged users +- Resolves: RHEL-23621 session cookie can't be read +- Resolves: RHEL-22372 Gating-DL1 test failure in test_integration/test_dns_locations.py::TestDNSLocations::()::test_ipa_ca_records +- Resolves: RHEL-21809 CA less servers are failing to be added in topology segment for domain suffix +- Resolves: RHEL-17996 Memory leak in IdM's KDC + +* Thu Jan 18 2024 Florence Blanc-Renaud - 4.11.0-5 +- Resolves: RHEL-12589 ipa: Invalid CSRF protection +- Resolves: RHEL-19748 ipa hbac-test did not report that it hit an arbitrary search limit +- Resolves: RHEL-21059 'DogtagCertsConfigCheck' fails, displaying the error message 'Malformed directive: ca.signing.certnickname=caSigningCert cert-pki-ca' +- Resolves: RHEL-21804 ipa client 4.10.2 - Failed to obtain host TGT +- Resolves: RHEL-21809 CA less servers are failing to be added in topology segment for domain suffix +- Resolves: RHEL-21810 ipa-client-install --automount-location does not work +- Resolves: RHEL-21811 Handle change in behavior of pki-server ca-config-show in pki 11.5.0 +- Resolves: RHEL-21812 Backport latest test fixes in ipa +- Resolves: RHEL-21813 krb5kdc fails to start when pkinit and otp auth type is enabled in ipa +- Resolves: RHEL-21815 IPA 389ds plugins need to have better logging and tracing +- Resolves: RHEL-21937 Make sure a default NetBIOS name is set if not passed in by ADTrust instance constructor + +* Fri Dec 1 2023 Florence Blanc-Renaud - 4.11.0-4 +- Resolves: RHEL-16985 Handle samba 4.19 changes in samba.security.dom_sid() + +* Mon Nov 20 2023 Florence Blanc-Renaud - 4.11.0-3 +- Resolves: RHEL-14428 healthcheck reports nsslapd-accesslog-logbuffering is set to 'off' + +* Mon Nov 6 2023 Florence Blanc-Renaud - 4.11.0-2 +- Resolves: RHEL-14292 Backport latest test fixes in python3-ipatests +- Resolves: RHEL-15443 Server install: failure to install with externally signed CA because of timezone issue +- Resolves: RHEL-15444 Minimum length parameter in pwpolicy cannot be removed with empty string +- Resolves: RHEL-14842 Upstream xmlrpc tests are failing in RHEL9.4 + +* Fri Oct 06 2023 Florence Blanc-Renaud - 4.11.0-1 +- Resolves: RHEL-11652 Rebase ipa to latest 4.11.x version for RHEL 9.4 + * Thu Aug 17 2023 Florence Blanc-Renaud - 4.10.2-4 - Resolves: rhbz#2231847 RHEL 8.8 & 9.2 fails to create AD trust with STIG applied - Resolves: rhbz#2232056 Include latest test fixes in python3-ipatests