From ed508b4be8e09c553379c2b69e13851e19ca2ae5 Mon Sep 17 00:00:00 2001 From: Florence Blanc-Renaud Date: Wed, 15 Jan 2025 18:19:41 +0100 Subject: [PATCH] ipa-4.12.2-8 - Resolves: RHEL-73022 A slow HSM can cause IPA server installation to fail setting up certificate tracking [rhel-9] - Resolves: RHEL-71261 [RHEL-9.6] Include latest fixes in python3-ipatests package - Resolves: RHEL-67191 CVE-2024-11029 ipa: Administrative user data leaked through systemd journal [rhel-9.6] - Resolves: RHEL-59040 KRA installation failure caused by a certificate mismatch in NSS DB and configuration file. Signed-off-by: Florence Blanc-Renaud --- ...eck-skip-connectivity_and_data-check.patch | 35 + ...sts-Fixes-for-ipa-ipa-migration-tool.patch | 36 + ...st-KRA-on-replica-after-cert-renewal.patch | 47 ++ ...-update-ca.connector.KRA.transportCe.patch | 45 ++ ...meout-for-certmonger-request-start-t.patch | 45 ++ 0043-Unify-use-of-option-parsers.patch | 624 ++++++++++++++++++ ...-sensitive-material-from-the-command.patch | 422 ++++++++++++ ...c_child-s-client-secret-stdin-option.patch | 75 +++ ...Fix-pylint-issue-in-ipatests-i18n.py.patch | 69 ++ freeipa.spec | 17 +- 10 files changed, 1414 insertions(+), 1 deletion(-) create mode 100644 0038-test_ipahealthcheck-skip-connectivity_and_data-check.patch create mode 100644 0039-ipatests-Fixes-for-ipa-ipa-migration-tool.patch create mode 100644 0040-Installation-test-KRA-on-replica-after-cert-renewal.patch create mode 100644 0041-KRA-cert-renewal-update-ca.connector.KRA.transportCe.patch create mode 100644 0042-Add-30-second-timeout-for-certmonger-request-start-t.patch create mode 100644 0043-Unify-use-of-option-parsers.patch create mode 100644 0044-ipa-tools-remove-sensitive-material-from-the-command.patch create mode 100644 0045-ipa-otpd-use-oidc_child-s-client-secret-stdin-option.patch create mode 100644 0046-Fix-pylint-issue-in-ipatests-i18n.py.patch diff --git a/0038-test_ipahealthcheck-skip-connectivity_and_data-check.patch b/0038-test_ipahealthcheck-skip-connectivity_and_data-check.patch new file mode 100644 index 0000000..c13ec2a --- /dev/null +++ b/0038-test_ipahealthcheck-skip-connectivity_and_data-check.patch @@ -0,0 +1,35 @@ +From d8d4c5507bd3784d323e6836ff8456ba9608f115 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 20 Sep 2024 09:36:41 +0200 +Subject: [PATCH] test_ipahealthcheck: skip connectivity_and_data check + +PKI removed the clones.check connectivity_and_data check in +11.5 and master branches. Skip the test depending on PKI version. +The most recent version on 11.5 is 11.5.4 and still contains the check, +hence skipping if version >= 11.5.5. + +Fixes: https://pagure.io/freeipa/issue/9668 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_ipahealthcheck.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py +index a3e10b04487f0a12fdde19a8d1971a09f7d79b63..cc51a5a6a62fbc50927fc2fc51f129a069e70b69 100644 +--- a/ipatests/test_integration/test_ipahealthcheck.py ++++ b/ipatests/test_integration/test_ipahealthcheck.py +@@ -1219,6 +1219,9 @@ class TestIpaHealthCheck(IntegrationTest): + This testcase checks that when ClonesConnectivyAndDataCheck + is run it doesn't display source not found error + """ ++ if (tasks.get_pki_version( ++ self.master) >= tasks.parse_version('11.5.5')): ++ raise pytest.skip("PKI dropped ClonesConnectivyAndDataCheck") + error_msg = ( + "Source 'pki.server.healthcheck.clones.connectivity_and_data' " + "not found" +-- +2.47.1 + diff --git a/0039-ipatests-Fixes-for-ipa-ipa-migration-tool.patch b/0039-ipatests-Fixes-for-ipa-ipa-migration-tool.patch new file mode 100644 index 0000000..dffb3c4 --- /dev/null +++ b/0039-ipatests-Fixes-for-ipa-ipa-migration-tool.patch @@ -0,0 +1,36 @@ +From c294b7f6dbcae9c01d5366b19b3b070ffb730fa6 Mon Sep 17 00:00:00 2001 +From: Sudhir Menon +Date: Wed, 11 Dec 2024 15:12:48 +0530 +Subject: [PATCH] ipatests: Fixes for ipa-ipa-migration tool + +The test test_ipa_migrate_with_invalid_host has been +failing in downstream run due to mismatch in the expected test output, +hence the assert statement has been modified. + +Related: https://pagure.io/freeipa/issue/3656 + +Signed-off-by: Sudhir Menon +Reviewed-By: Florence Blanc-Renaud +--- + ipatests/test_integration/test_ipa_ipa_migration.py | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py +index 0c637a0141d95f34f951c60a9648adf8e87eaa63..95c29234fc7893d3eae5d900a58aa7b1162ed61d 100644 +--- a/ipatests/test_integration/test_ipa_ipa_migration.py ++++ b/ipatests/test_integration/test_ipa_ipa_migration.py +@@ -437,10 +437,8 @@ class TestIPAMigrateCLIOptions(MigrationTest): + """ + hostname = "server.invalid.host" + ERR_MSG = ( +- "IPA to IPA migration starting ...\n" + "Failed to bind to remote server: cannot connect to " +- "'ldap://" +- "{}': \n".format(hostname) ++ "'ldap://{}':".format(hostname) + ) + result = run_migrate( + self.replicas[0], +-- +2.47.1 + diff --git a/0040-Installation-test-KRA-on-replica-after-cert-renewal.patch b/0040-Installation-test-KRA-on-replica-after-cert-renewal.patch new file mode 100644 index 0000000..ce5085c --- /dev/null +++ b/0040-Installation-test-KRA-on-replica-after-cert-renewal.patch @@ -0,0 +1,47 @@ +From ff5bb485d709ea02422cbafba51d23db384822af Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 20 Dec 2024 15:45:01 +0100 +Subject: [PATCH] Installation test: KRA on replica after cert renewal + +Add a new test installing the KRA on a replica after the +KRA certs have been renewed on the master. + +Related: https://pagure.io/freeipa/issue/9692 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_installation.py | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py +index c5565c452010f23f038ddf329454b591ef09f6af..1fae472673a3934c86af2f9adc7b343c70e25b2b 100644 +--- a/ipatests/test_integration/test_installation.py ++++ b/ipatests/test_integration/test_installation.py +@@ -1322,7 +1322,7 @@ class TestInstallMaster(IntegrationTest): + + class TestInstallMasterKRA(IntegrationTest): + +- num_replicas = 0 ++ num_replicas = 1 + + @classmethod + def install(cls, mh): +@@ -1379,6 +1379,14 @@ class TestInstallMasterKRA(IntegrationTest): + ) + assert starting_serial != int(cert.serial_number) + ++ def test_install_replica_after_kracert_renewal(self): ++ """ ++ Test replica installation with CA after the KRA certs renewal ++ """ ++ tasks.install_replica(self.master, self.replicas[0], ++ setup_ca=True) ++ tasks.install_kra(self.replicas[0]) ++ + + class TestInstallMasterDNS(IntegrationTest): + +-- +2.47.1 + diff --git a/0041-KRA-cert-renewal-update-ca.connector.KRA.transportCe.patch b/0041-KRA-cert-renewal-update-ca.connector.KRA.transportCe.patch new file mode 100644 index 0000000..1666f04 --- /dev/null +++ b/0041-KRA-cert-renewal-update-ca.connector.KRA.transportCe.patch @@ -0,0 +1,45 @@ +From a707083b0987e6ffabb817fcc5e5138b4c755459 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 20 Dec 2024 17:01:56 +0100 +Subject: [PATCH] KRA cert renewal: update ca.connector.KRA.transportCert + +After the KRA transport cert has been renewed, the value +of ca.connector.KRA.transportCert must also be updated in +/etc/pki/pki-tomcat/ca/CS.cfg. +Otherwise replica installation with KRA fails. + +Fixes: https://pagure.io/freeipa/issue/9692 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/install/cainstance.py | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 5c2c9f8b981cf5d587865f7680e2b231eae655e2..e03a8c863e14782679e19c6887f5e220131e4234 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -1225,11 +1225,14 @@ class CAInstance(DogtagInstance): + """ + + # The cert directive to update per nickname +- directives = {'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert', +- 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert', +- 'caSigningCert cert-pki-ca': 'ca.signing.cert', +- 'subsystemCert cert-pki-ca': 'ca.subsystem.cert', +- 'Server-Cert cert-pki-ca': 'ca.sslserver.cert'} ++ directives = { ++ 'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert', ++ 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert', ++ 'caSigningCert cert-pki-ca': 'ca.signing.cert', ++ 'subsystemCert cert-pki-ca': 'ca.subsystem.cert', ++ 'Server-Cert cert-pki-ca': 'ca.sslserver.cert', ++ 'transportCert cert-pki-kra': 'ca.connector.KRA.transportCert' ++ } + + try: + self.backup_config() +-- +2.47.1 + diff --git a/0042-Add-30-second-timeout-for-certmonger-request-start-t.patch b/0042-Add-30-second-timeout-for-certmonger-request-start-t.patch new file mode 100644 index 0000000..53dfeb2 --- /dev/null +++ b/0042-Add-30-second-timeout-for-certmonger-request-start-t.patch @@ -0,0 +1,45 @@ +From 2506d5de5a9dd8ebe6efc777c2eb76461f5b57e2 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 6 Jan 2025 10:12:15 -0500 +Subject: [PATCH] Add 30-second timeout for certmonger request/start tracking + +certmonger needs to validate that the PIN/password and/or token +are valid and available. In the case of a very slow HSM this can +take longer than the 5-second default timeout. + +We saw an HSM that took 18 seconds to start tracking the CA signing +certificate so default to 30 to be safe. + +Fixes: https://pagure.io/freeipa/issue/9725 + +Signed-off-by: Rob Crittenden +Reviewed-By: Alexander Bokovoy +--- + ipalib/install/certmonger.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py +index 7b22295152f752b6ab4de0f3525d48c541677aff..efc1ba4f42eab98df5fac51bafa3acc83ae91831 100644 +--- a/ipalib/install/certmonger.py ++++ b/ipalib/install/certmonger.py +@@ -477,7 +477,7 @@ def request_cert( + request_parameters['cert-perms'] = perms[0] + request_parameters['key-perms'] = perms[1] + +- result = cm.obj_if.add_request(request_parameters) ++ result = cm.obj_if.add_request(request_parameters, timeout=30) + try: + if result[0]: + request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF, +@@ -581,7 +581,7 @@ def start_tracking( + if nss_user: + params['nss-user'] = nss_user + +- result = cm.obj_if.add_request(params) ++ result = cm.obj_if.add_request(params, timeout=30) + try: + if result[0]: + request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF, +-- +2.47.1 + diff --git a/0043-Unify-use-of-option-parsers.patch b/0043-Unify-use-of-option-parsers.patch new file mode 100644 index 0000000..3147117 --- /dev/null +++ b/0043-Unify-use-of-option-parsers.patch @@ -0,0 +1,624 @@ +From d26ce5cccc211f83b3cce3fc5e548b5cb955bb81 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 13 Dec 2024 13:42:36 +0200 +Subject: [PATCH] Unify use of option parsers + +Do not use direct optparse references, instead import IPAOptionParser + +Signed-off-by: Alexander Bokovoy +--- + install/tools/ipa-adtrust-install.in | 4 +--- + install/tools/ipa-managed-entries.in | 3 ++- + ipaclient/install/ipa_client_automount.py | 4 ++-- + ipaclient/install/ipa_client_samba.py | 4 ++-- + ipalib/cli.py | 21 ++++++++++++--------- + ipalib/plugable.py | 8 ++++---- + ipapython/admintool.py | 3 +-- + ipapython/config.py | 18 +++++++++++------- + ipapython/install/cli.py | 9 ++++----- + ipaserver/install/ipa_acme_manage.py | 6 ++---- + ipaserver/install/ipa_backup.py | 5 ++--- + ipaserver/install/ipa_cacert_manage.py | 9 ++++----- + ipaserver/install/ipa_kra_install.py | 5 ++--- + ipaserver/install/ipa_restore.py | 5 ++--- + ipaserver/install/ipa_server_certinstall.py | 7 +++---- + ipatests/i18n.py | 8 ++++---- + makeapi.in | 5 ++--- + 17 files changed, 60 insertions(+), 64 deletions(-) + +diff --git a/install/tools/ipa-adtrust-install.in b/install/tools/ipa-adtrust-install.in +index cb2b78e504896b96cdc378fd879cc1f00c60904f..e7b0e369259da5d28d703558d9293ccfaf68f3ed 100644 +--- a/install/tools/ipa-adtrust-install.in ++++ b/install/tools/ipa-adtrust-install.in +@@ -29,8 +29,6 @@ import sys + + import six + +-from optparse import SUPPRESS_HELP # pylint: disable=deprecated-module +- + from ipalib.install import sysrestore + from ipaserver.install import adtrust, service + from ipaserver.install.installutils import ( +@@ -41,7 +39,7 @@ from ipapython.admintool import ScriptError + from ipapython import version + from ipapython import ipautil + from ipalib import api, errors, krb_utils +-from ipapython.config import IPAOptionParser ++from ipapython.config import IPAOptionParser, SUPPRESS_HELP + from ipaplatform.paths import paths + from ipapython.ipa_log_manager import standard_logging_setup + +diff --git a/install/tools/ipa-managed-entries.in b/install/tools/ipa-managed-entries.in +index e9be41b7a34ed62e65ab40bf544a6e4cea7c598a..e3f121943eb3b18ca8f7f8bfeae7813cbc9bd753 100644 +--- a/install/tools/ipa-managed-entries.in ++++ b/install/tools/ipa-managed-entries.in +@@ -39,7 +39,8 @@ logger = logging.getLogger(os.path.basename(__file__)) + def parse_options(): + usage = "%prog [options] \n" + usage += "%prog [options]\n" +- parser = OptionParser(usage=usage, formatter=config.IPAFormatter()) ++ parser = config.IPAOptionParser(usage=usage, ++ formatter=config.IPAFormatter()) + + parser.add_option("-d", "--debug", action="store_true", dest="debug", + help="Display debugging information about the update(s)") +diff --git a/ipaclient/install/ipa_client_automount.py b/ipaclient/install/ipa_client_automount.py +index 4439932bd723c40c429dac2c08e97d326e414d24..9f49ff9edeee2648d2be1dea6b09806ba0b5e041 100644 +--- a/ipaclient/install/ipa_client_automount.py ++++ b/ipaclient/install/ipa_client_automount.py +@@ -34,7 +34,6 @@ import SSSDConfig + + from six.moves.urllib.parse import urlsplit + +-from optparse import OptionParser # pylint: disable=deprecated-module + from ipapython import ipachangeconf + from ipaclient import discovery + from ipaclient.install.client import ( +@@ -52,6 +51,7 @@ from ipaplatform.tasks import tasks + from ipaplatform import services + from ipaplatform.paths import paths + from ipapython.admintool import ScriptError ++from ipapython.config import IPAOptionParser + + + logger = logging.getLogger(os.path.basename(__file__)) +@@ -59,7 +59,7 @@ logger = logging.getLogger(os.path.basename(__file__)) + + def parse_options(): + usage = "%prog [options]\n" +- parser = OptionParser(usage=usage) ++ parser = IPAOptionParser(usage=usage) + parser.add_option("--server", dest="server", help="FQDN of IPA server") + parser.add_option( + "--location", +diff --git a/ipaclient/install/ipa_client_samba.py b/ipaclient/install/ipa_client_samba.py +index 81d670c34cae0f91a436a2a2d1e0d525057b6cc7..5c33abb4cabe47ff311b7d769fefa37991f7d453 100755 +--- a/ipaclient/install/ipa_client_samba.py ++++ b/ipaclient/install/ipa_client_samba.py +@@ -9,7 +9,6 @@ import logging + import os + import gssapi + from urllib.parse import urlsplit +-from optparse import OptionParser # pylint: disable=deprecated-module + from contextlib import contextmanager + + from ipaclient import discovery +@@ -31,6 +30,7 @@ from ipaplatform.constants import constants + from ipaplatform import services + from ipapython.admintool import ScriptError + from samba import generate_random_password ++from ipapython.config import IPAOptionParser + + logger = logging.getLogger(os.path.basename(__file__)) + logger.setLevel(logging.DEBUG) +@@ -68,7 +68,7 @@ def use_api_as_principal(principal, keytab): + + def parse_options(): + usage = "%prog [options]\n" +- parser = OptionParser(usage=usage) ++ parser = IPAOptionParser(usage=usage) + parser.add_option( + "--server", + dest="server", +diff --git a/ipalib/cli.py b/ipalib/cli.py +index d9c2ac16513101098c8f9a2258ae930b3b2cebf0..667b213fd4e4706e6eecd4d2b4737fb3fede4c93 100644 +--- a/ipalib/cli.py ++++ b/ipalib/cli.py +@@ -30,7 +30,6 @@ import textwrap + import sys + import getpass + import code +-import optparse # pylint: disable=deprecated-module + import os + import pprint + import fcntl +@@ -71,6 +70,8 @@ from ipalib.text import _ + from ipalib import api + from ipapython.dnsutil import DNSName + from ipapython.admintool import ScriptError ++from ipapython.config import (IPAOptionParser, IPAFormatter, ++ OptionGroup, make_option) + + import datetime + +@@ -1121,7 +1122,8 @@ class Collector: + def __todict__(self): + return dict(self.__options) + +-class CLIOptionParserFormatter(optparse.IndentedHelpFormatter): ++ ++class CLIOptionParserFormatter(IPAFormatter): + def format_argument(self, name, help_string): + result = [] + opt_width = self.help_position - self.current_indent - 2 +@@ -1141,7 +1143,8 @@ class CLIOptionParserFormatter(optparse.IndentedHelpFormatter): + result.append("\n") + return "".join(result) + +-class CLIOptionParser(optparse.OptionParser): ++ ++class CLIOptionParser(IPAOptionParser): + """ + This OptionParser subclass adds an ability to print positional + arguments in CLI help. Custom formatter is used to format the argument +@@ -1151,13 +1154,13 @@ class CLIOptionParser(optparse.OptionParser): + self._arguments = [] + if 'formatter' not in kwargs: + kwargs['formatter'] = CLIOptionParserFormatter() +- optparse.OptionParser.__init__(self, *args, **kwargs) ++ IPAOptionParser.__init__(self, *args, **kwargs) + + def format_option_help(self, formatter=None): + """ + Prepend argument help to standard OptionParser's option help + """ +- option_help = optparse.OptionParser.format_option_help(self, formatter) ++ option_help = IPAOptionParser.format_option_help(self, formatter) + + if isinstance(formatter, CLIOptionParserFormatter): + heading = unicode(_("Positional arguments")) +@@ -1272,7 +1275,7 @@ class cli(backend.Executioner): + """Get or create an option group for the given name""" + option_group = option_groups.get(group_name) + if option_group is None: +- option_group = optparse.OptionGroup(parser, group_name) ++ option_group = OptionGroup(parser, group_name) + parser.add_option_group(option_group) + option_groups[group_name] = option_group + return option_group +@@ -1298,7 +1301,7 @@ class cli(backend.Executioner): + option_names = ['--%s' % cli_name] + if option.cli_short_name: + option_names.append('-%s' % option.cli_short_name) +- opt = optparse.make_option(*option_names, **kw) ++ opt = make_option(*option_names, **kw) + if option.option_group is None: + parser.add_option(opt) + else: +@@ -1312,7 +1315,7 @@ class cli(backend.Executioner): + group = _get_option_group(unicode(_('Deprecated options'))) + for alias in option.deprecated_cli_aliases: + name = '--%s' % alias +- group.add_option(optparse.make_option(name, **new_kw)) ++ group.add_option(make_option(name, **new_kw)) + + for arg in cmd.args(): + name = self.__get_arg_name(arg, format_name=False) +@@ -1442,7 +1445,7 @@ class cli(backend.Executioner): + ) + + +-class IPAHelpFormatter(optparse.IndentedHelpFormatter): ++class IPAHelpFormatter(IPAFormatter): + """Formatter suitable for printing IPA command help + + The default help formatter reflows text to fit the terminal, but it +diff --git a/ipalib/plugable.py b/ipalib/plugable.py +index 2e2861df054fa7ed3533d0f82a23b65322ab591b..a87e6e8914fa5579920aad8190c7f6a86cb3dfea 100644 +--- a/ipalib/plugable.py ++++ b/ipalib/plugable.py +@@ -33,7 +33,6 @@ import sys + import threading + import os + from os import path +-import optparse # pylint: disable=deprecated-module + import textwrap + import collections + import importlib +@@ -47,6 +46,7 @@ from ipalib.util import classproperty + from ipalib.base import ReadOnly, lock, islocked + from ipalib.constants import DEFAULT_CONFIG + from ipapython import ipa_log_manager, ipautil ++from ipapython.config import IPAOptionParser, IPAFormatter + from ipapython.ipa_log_manager import ( + LOGGING_FORMAT_FILE, + LOGGING_FORMAT_STDERR) +@@ -526,7 +526,7 @@ class API(ReadOnly): + + def build_global_parser(self, parser=None, context=None): + """ +- Add global options to an optparse.OptionParser instance. ++ Add global options to an IPAOptionParser instance. + """ + def config_file_callback(option, opt, value, parser): + if not os.path.isfile(value): +@@ -536,7 +536,7 @@ class API(ReadOnly): + parser.values.conf = value + + if parser is None: +- parser = optparse.OptionParser( ++ parser = IPAOptionParser( + add_help_option=False, + formatter=IPAHelpFormatter(), + usage='%prog [global-options] COMMAND [command-options]', +@@ -821,7 +821,7 @@ class API(ReadOnly): + return self.__next[plugin] + + +-class IPAHelpFormatter(optparse.IndentedHelpFormatter): ++class IPAHelpFormatter(IPAFormatter): + def format_epilog(self, epilog): + text_width = self.width - self.current_indent + indent = " " * self.current_indent +diff --git a/ipapython/admintool.py b/ipapython/admintool.py +index fdb4400d879165612405b3ba159a220773bd8d69..dff9112eba4009d2fc1a6202756c6671ba4d909d 100644 +--- a/ipapython/admintool.py ++++ b/ipapython/admintool.py +@@ -26,7 +26,6 @@ import logging + import sys + import os + import traceback +-from optparse import OptionGroup # pylint: disable=deprecated-module + + from ipaplatform.osinfo import osinfo + from ipapython import version +@@ -113,7 +112,7 @@ class AdminTool: + :param parser: The parser to add options to + :param debug_option: Add a --debug option as an alias to --verbose + """ +- group = OptionGroup(parser, "Logging and output options") ++ group = config.OptionGroup(parser, "Logging and output options") + group.add_option("-v", "--verbose", dest="verbose", default=False, + action="store_true", help="print debugging information") + if debug_option: +diff --git a/ipapython/config.py b/ipapython/config.py +index f53d0f998aaedf47715764577dd7f5048f4ca841..7af4dfdeb0047586de9694f233be8bf543190b9c 100644 +--- a/ipapython/config.py ++++ b/ipapython/config.py +@@ -18,9 +18,9 @@ + # + from __future__ import absolute_import + +-# pylint: disable=deprecated-module +-from optparse import ( +- Option, Values, OptionParser, IndentedHelpFormatter, OptionValueError) ++# pylint: disable=deprecated-module, disable=unused-import ++from optparse import (Option, Values, OptionGroup, OptionParser, SUPPRESS_HELP, ++ IndentedHelpFormatter, OptionValueError, make_option) + # pylint: enable=deprecated-module + from copy import copy + from configparser import ConfigParser as SafeConfigParser +@@ -113,10 +113,14 @@ class IPAOptionParser(OptionParser): + description=None, + formatter=None, + add_help_option=True, +- prog=None): +- OptionParser.__init__(self, usage, option_list, option_class, +- version, conflict_handler, description, +- formatter, add_help_option, prog) ++ prog=None, ++ epilog=None): ++ OptionParser.__init__(self, usage=usage, option_list=option_list, ++ option_class=option_class, version=version, ++ conflict_handler=conflict_handler, ++ description=description, formatter=formatter, ++ add_help_option=add_help_option, prog=prog, ++ epilog=epilog) + + def get_safe_opts(self, opts): + """ +diff --git a/ipapython/install/cli.py b/ipapython/install/cli.py +index ab212be4e2c3f9c2aae97f7759672ef7c68c3347..a048b3c7c64bc22338e4517d64b33a44446c58a3 100644 +--- a/ipapython/install/cli.py ++++ b/ipapython/install/cli.py +@@ -9,12 +9,11 @@ Command line support. + import collections + import enum + import logging +-import optparse # pylint: disable=deprecated-module + import signal + + import six + +-from ipapython import admintool ++from ipapython import admintool, config + from ipapython.ipa_log_manager import standard_logging_setup + from ipapython.ipautil import (CheckedIPAddress, CheckedIPAddressLoopback, + private_ccache) +@@ -158,7 +157,7 @@ class ConfigureTool(admintool.AdminTool): + try: + opt_group = groups[group_cls] + except KeyError: +- opt_group = groups[group_cls] = optparse.OptionGroup( ++ opt_group = groups[group_cls] = config.OptionGroup( + parser, "{0} options".format(group_cls.description)) + parser.add_option_group(opt_group) + +@@ -232,7 +231,7 @@ class ConfigureTool(admintool.AdminTool): + if not hidden: + help = knob_cls.description + else: +- help = optparse.SUPPRESS_HELP ++ help = config.SUPPRESS_HELP + + opt_group.add_option( + *opt_strs, +@@ -256,7 +255,7 @@ class ConfigureTool(admintool.AdminTool): + + # fake option parser to parse positional arguments + # (because optparse does not support positional argument parsing) +- fake_option_parser = optparse.OptionParser() ++ fake_option_parser = config.IPAOptionParser() + self.add_options(fake_option_parser, True) + + fake_option_map = {option.dest: option +diff --git a/ipaserver/install/ipa_acme_manage.py b/ipaserver/install/ipa_acme_manage.py +index dc2359f49dfdd5c8f44ab96ee11a7240f8937e11..0decab394c1c18067fe0c194c040805a8d93d42d 100644 +--- a/ipaserver/install/ipa_acme_manage.py ++++ b/ipaserver/install/ipa_acme_manage.py +@@ -7,14 +7,12 @@ import enum + import pki.util + import logging + +-from optparse import OptionGroup # pylint: disable=deprecated-module +- + from ipalib import api, errors, x509 + from ipalib import _ + from ipalib.facts import is_ipa_configured + from ipaplatform.paths import paths + from ipapython.admintool import AdminTool +-from ipapython import cookie, dogtag ++from ipapython import cookie, dogtag, config + from ipapython.ipautil import run + from ipapython.certdb import NSSDatabase, EXTERNAL_CA_TRUST_FLAGS + from ipaserver.install import cainstance +@@ -143,7 +141,7 @@ class IPAACMEManage(AdminTool): + @classmethod + def add_options(cls, parser): + +- group = OptionGroup(parser, 'Pruning') ++ group = config.OptionGroup(parser, 'Pruning') + group.add_option( + "--enable", dest="enable", action="store_true", + default=False, help="Enable certificate pruning") +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 982e5dfc4c0339aada88f936ab450b7fc16944f2..b6af63813fc4eaadab44ad95386d86ae4f1e21ee 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -20,7 +20,6 @@ + from __future__ import absolute_import, print_function + + import logging +-import optparse # pylint: disable=deprecated-module + import os + import shutil + import sys +@@ -32,7 +31,7 @@ import six + from ipaplatform.paths import paths + from ipaplatform import services + from ipalib import api, errors +-from ipapython import version ++from ipapython import version, config + from ipapython.ipautil import run, write_tmp_file + from ipapython import admintool, certdb + from ipapython.dn import DN +@@ -245,7 +244,7 @@ class Backup(admintool.AdminTool): + + parser.add_option( + "--gpg-keyring", dest="gpg_keyring", +- help=optparse.SUPPRESS_HELP) ++ help=config.SUPPRESS_HELP) + parser.add_option( + "--gpg", dest="gpg", action="store_true", + default=False, help="Encrypt the backup") +diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py +index f6ab736fa985b00ba66a7001c4c4e2188841bcbe..048245237855212afe1f3ec4795b2253026ef864 100644 +--- a/ipaserver/install/ipa_cacert_manage.py ++++ b/ipaserver/install/ipa_cacert_manage.py +@@ -22,14 +22,13 @@ from __future__ import print_function, absolute_import + import datetime + import logging + import os +-from optparse import OptionGroup # pylint: disable=deprecated-module + import gssapi + + from ipalib.constants import ( + RENEWAL_CA_NAME, RENEWAL_REUSE_CA_NAME, RENEWAL_SELFSIGNED_CA_NAME, + IPA_CA_CN) + from ipalib.install import certmonger, certstore +-from ipapython import admintool, ipautil ++from ipapython import admintool, ipautil, config + from ipapython.certdb import (EMPTY_TRUST_FLAGS, + EXTERNAL_CA_TRUST_FLAGS, + TrustFlags, +@@ -61,7 +60,7 @@ class CACertManage(admintool.AdminTool): + "-p", "--password", dest='password', + help="Directory Manager password") + +- renew_group = OptionGroup(parser, "Renew options") ++ renew_group = config.OptionGroup(parser, "Renew options") + renew_group.add_option( + "--self-signed", dest='self_signed', + action='store_true', +@@ -89,7 +88,7 @@ class CACertManage(admintool.AdminTool): + "certificate chain") + parser.add_option_group(renew_group) + +- install_group = OptionGroup(parser, "Install options") ++ install_group = config.OptionGroup(parser, "Install options") + install_group.add_option( + "-n", "--nickname", dest='nickname', + help="Nickname for the certificate") +@@ -98,7 +97,7 @@ class CACertManage(admintool.AdminTool): + help="Trust flags for the certificate in certutil format") + parser.add_option_group(install_group) + +- delete_group = OptionGroup(parser, "Delete options") ++ delete_group = config.OptionGroup(parser, "Delete options") + delete_group.add_option( + "-f", "--force", action='store_true', + help="Force removing the CA even if chain validation fails") +diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py +index 3e4cd67fa677db2534a639eb6beb14dfd78bf035..8a09179f7fa0c2ddad72d01e9c3eaf98575d0a88 100644 +--- a/ipaserver/install/ipa_kra_install.py ++++ b/ipaserver/install/ipa_kra_install.py +@@ -22,13 +22,12 @@ from __future__ import print_function, absolute_import + import logging + import sys + import tempfile +-from optparse import SUPPRESS_HELP # pylint: disable=deprecated-module + + from textwrap import dedent + from ipalib import api + from ipalib.constants import DOMAIN_LEVEL_1 + from ipaplatform.paths import paths +-from ipapython import admintool ++from ipapython import admintool, config + from ipaserver.install import service + from ipaserver.install import cainstance + from ipaserver.install import custodiainstance +@@ -73,7 +72,7 @@ class KRAInstall(admintool.AdminTool): + parser.add_option( + "--uninstall", + dest="uninstall", action="store_true", default=False, +- help=SUPPRESS_HELP) ++ help=config.SUPPRESS_HELP) + + parser.add_option( + "--pki-config-override", dest="pki_config_override", +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index 57ad8dd05206132d3458fa84e7fb996b135f7f71..8d75a0e6beba09086bc2ce8c73f3bcfe81e52113 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -20,7 +20,6 @@ + from __future__ import absolute_import, print_function + + import logging +-import optparse # pylint: disable=deprecated-module + import os + import shutil + import sys +@@ -34,7 +33,7 @@ import six + from ipaclient.install.client import update_ipa_nssdb + from ipalib import api, errors + from ipalib.constants import FQDN +-from ipapython import version, ipautil ++from ipapython import version, ipautil, config + from ipapython.ipautil import run, user_input + from ipapython import admintool, certdb + from ipapython.dn import DN +@@ -190,7 +189,7 @@ class Restore(admintool.AdminTool): + help="Directory Manager password") + parser.add_option( + "--gpg-keyring", dest="gpg_keyring", +- help=optparse.SUPPRESS_HELP) ++ help=config.SUPPRESS_HELP) + parser.add_option( + "--data", dest="data_only", action="store_true", + default=False, help="Restore only the data") +diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py +index e29f00ec37779aeb10255c5df6e10d6ecc0a6d11..e9f680b1d1e505f89fc1611b8dbb3f84768f6781 100644 +--- a/ipaserver/install/ipa_server_certinstall.py ++++ b/ipaserver/install/ipa_server_certinstall.py +@@ -22,12 +22,11 @@ from __future__ import print_function, absolute_import + import os + import os.path + import tempfile +-import optparse # pylint: disable=deprecated-module + + from ipalib import x509 + from ipalib.install import certmonger + from ipaplatform.paths import paths +-from ipapython import admintool, dogtag ++from ipapython import admintool, dogtag, config + from ipapython.certdb import NSSDatabase, get_ca_nickname + from ipapython.dn import DN + from ipapython import ipaldap +@@ -65,8 +64,8 @@ class ServerCertInstall(admintool.AdminTool): + help="The password of the PKCS#12 file") + parser.add_option( + "--dirsrv_pin", "--http_pin", +- dest="pin", +- help=optparse.SUPPRESS_HELP) ++ dest="pin", sensitive=True, ++ help=config.SUPPRESS_HELP) + parser.add_option( + "--cert-name", + dest="cert_name", metavar="NAME", +diff --git a/ipatests/i18n.py b/ipatests/i18n.py +index 49f5c4c3232346db3147bd7a5ba8056344ac907f..57915c286be72124fa23380f97f3922496f00c22 100644 +--- a/ipatests/i18n.py ++++ b/ipatests/i18n.py +@@ -22,7 +22,6 @@ from __future__ import print_function + + # WARNING: Do not import ipa modules, this is also used as a + # stand-alone script (invoked from po Makefile). +-import optparse # pylint: disable=deprecated-module + import sys + import gettext + import re +@@ -30,6 +29,7 @@ import os + import traceback + import polib + from collections import namedtuple ++from ipapython import config + + import six + +@@ -722,9 +722,9 @@ usage =''' + def main(): + global verbose, print_traceback, pedantic, show_strings + +- parser = optparse.OptionParser(usage=usage) ++ parser = config.IPAOptionParser(usage=usage) + +- mode_group = optparse.OptionGroup(parser, 'Operational Mode', ++ mode_group = config.OptionGroup(parser, 'Operational Mode', + 'You must select one these modes to run in') + + mode_group.add_option('-g', '--test-gettext', action='store_const', const='test_gettext', dest='mode', +@@ -748,7 +748,7 @@ def main(): + parser.add_option('--traceback', action='store_true', dest='print_traceback', default=False, + help='print the traceback when an exception occurs') + +- param_group = optparse.OptionGroup(parser, 'Run Time Parameters', ++ param_group = config.OptionGroup(parser, 'Run Time Parameters', + 'These may be used to modify the run time defaults') + + param_group.add_option('--test-lang', action='store', dest='test_lang', default='test', +diff --git a/makeapi.in b/makeapi.in +index a801b9253db9500e0510fe591074ccf2e6d752c1..8fc87d23de743a6d661112ee616dce129a785a36 100644 +--- a/makeapi.in ++++ b/makeapi.in +@@ -38,6 +38,7 @@ from ipalib.parameters import Param + from ipalib.output import Output + from ipalib.text import Gettext, NGettext, ConcatenatedLazyText + from ipalib.capabilities import capabilities ++from ipapython import config + + API_FILE='API.txt' + +@@ -84,9 +85,7 @@ OUTPUT_IGNORED_ATTRIBUTES = ( + ) + + def parse_options(): +- from optparse import OptionParser # pylint: disable=deprecated-module +- +- parser = OptionParser() ++ parser = config.IPAOptionParser() + parser.add_option("--validate", dest="validate", action="store_true", + default=False, help="Validate the API vs the stored API") + +-- +2.47.1 + diff --git a/0044-ipa-tools-remove-sensitive-material-from-the-command.patch b/0044-ipa-tools-remove-sensitive-material-from-the-command.patch new file mode 100644 index 0000000..5556395 --- /dev/null +++ b/0044-ipa-tools-remove-sensitive-material-from-the-command.patch @@ -0,0 +1,422 @@ +From f9314562aaae03619eb89ae762bc24182174ad28 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 8 Nov 2024 14:59:20 +0200 +Subject: [PATCH] ipa tools: remove sensitive material from the commandline + +When command line tools accept passwords, remove them from the command +line so that they don't get visible in '/proc/pid/commandline'. + +There is no common method to access the original ARGV vector and modify +it from Python. Since this mostly affects Linux systems where IPA +services run, we expect use of GNU libc and thus can rely on internal +glibc symbols. If they aren't available, the code will skip removing +passwords. + +Fixes: CVE-2024-11029 + +Signed-off-by: Alexander Bokovoy +--- + .../com.redhat.idm.trust-fetch-domains.in | 5 ++- + install/tools/ipa-adtrust-install.in | 3 +- + install/tools/ipa-ca-install.in | 2 + + install/tools/ipa-compat-manage.in | 6 ++- + install/tools/ipa-csreplica-manage.in | 12 +++--- + install/tools/ipa-managed-entries.in | 5 ++- + install/tools/ipa-replica-conncheck.in | 7 ++-- + install/tools/ipa-replica-manage.in | 10 +++-- + ipapython/admintool.py | 40 +++++++++++++++++++ + ipaserver/install/ipa_migrate.py | 17 +++++++- + ipaserver/install/ipa_restore.py | 2 +- + ipaserver/install/ipa_server_certinstall.py | 2 +- + 12 files changed, 90 insertions(+), 21 deletions(-) + +diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains.in b/install/oddjob/com.redhat.idm.trust-fetch-domains.in +index 45c1f1463d5849d753c2913aa0b86b845cfce784..b86be0212c462e82d9379f55d5d3198c1017d2e7 100644 +--- a/install/oddjob/com.redhat.idm.trust-fetch-domains.in ++++ b/install/oddjob/com.redhat.idm.trust-fetch-domains.in +@@ -15,6 +15,7 @@ import six + import gssapi + + from ipalib.install.kinit import kinit_keytab, kinit_password ++from ipapython.admintool import admin_cleanup_global_argv + + if six.PY3: + unicode = str +@@ -52,11 +53,13 @@ def parse_options(): + "--password", + action="store", + dest="password", +- help="Display debugging information", ++ help="Password for Active Directory administrator", ++ sensitive=True + ) + + options, args = parser.parse_args() + safe_options = parser.get_safe_opts(options) ++ admin_cleanup_global_argv(parser, options, sys.argv) + + # We only use first argument of the passed args but as D-BUS interface + # in oddjobd cannot expose optional, we fill in empty slots from IPA side +diff --git a/install/tools/ipa-adtrust-install.in b/install/tools/ipa-adtrust-install.in +index e7b0e369259da5d28d703558d9293ccfaf68f3ed..1efccdb678d17410667b1721670bf6bf79152109 100644 +--- a/install/tools/ipa-adtrust-install.in ++++ b/install/tools/ipa-adtrust-install.in +@@ -35,7 +35,7 @@ from ipaserver.install.installutils import ( + read_password, + check_server_configuration, + run_script) +-from ipapython.admintool import ScriptError ++from ipapython.admintool import ScriptError, admin_cleanup_global_argv + from ipapython import version + from ipapython import ipautil + from ipalib import api, errors, krb_utils +@@ -93,6 +93,7 @@ def parse_options(): + + options, _args = parser.parse_args() + safe_options = parser.get_safe_opts(options) ++ admin_cleanup_global_argv(parser, options, sys.argv) + + return safe_options, options + +diff --git a/install/tools/ipa-ca-install.in b/install/tools/ipa-ca-install.in +index 9f3d16669679a245b73e044622ff52321524fcde..b437e761f760ab715c27bc330ac0f2e66e72ef5b 100644 +--- a/install/tools/ipa-ca-install.in ++++ b/install/tools/ipa-ca-install.in +@@ -42,6 +42,7 @@ from ipalib.constants import DOMAIN_LEVEL_1 + from ipapython.config import IPAOptionParser + from ipapython.ipa_log_manager import standard_logging_setup + from ipaplatform.paths import paths ++from ipapython.admintool import admin_cleanup_global_argv + + logger = logging.getLogger(os.path.basename(__file__)) + +@@ -132,6 +133,7 @@ def parse_options(): + + options, args = parser.parse_args() + safe_options = parser.get_safe_opts(options) ++ admin_cleanup_global_argv(parser, options, sys.argv) + + if args: + parser.error("Too many arguments provided") +diff --git a/install/tools/ipa-compat-manage.in b/install/tools/ipa-compat-manage.in +index 459f39fc826bbe6becd8be3517235af343d4b0d9..9650abd6f83ebc0a8ef347fee83989d4e9f13f09 100644 +--- a/install/tools/ipa-compat-manage.in ++++ b/install/tools/ipa-compat-manage.in +@@ -24,13 +24,13 @@ from __future__ import print_function + import sys + from ipaplatform.paths import paths + try: +- from optparse import OptionParser # pylint: disable=deprecated-module + from ipapython import ipautil, config + from ipaserver.install import installutils + from ipaserver.install.ldapupdate import LDAPUpdate + from ipalib import api, errors + from ipapython.ipa_log_manager import standard_logging_setup + from ipapython.dn import DN ++ from ipapython.admintool import admin_cleanup_global_argv + except ImportError as e: + print("""\ + There was a problem importing one of the required Python modules. The +@@ -46,7 +46,8 @@ nis_config_dn = DN(('cn', 'NIS Server'), ('cn', 'plugins'), ('cn', 'config')) + def parse_options(): + usage = "%prog [options] \n" + usage += "%prog [options]\n" +- parser = OptionParser(usage=usage, formatter=config.IPAFormatter()) ++ parser = config.IPAOptionParser(usage=usage, ++ formatter=config.IPAFormatter()) + + parser.add_option("-d", "--debug", action="store_true", dest="debug", + help="Display debugging information about the update(s)") +@@ -55,6 +56,7 @@ def parse_options(): + + config.add_standard_options(parser) + options, args = parser.parse_args() ++ admin_cleanup_global_argv(parser, options, sys.argv) + + return options, args + +diff --git a/install/tools/ipa-csreplica-manage.in b/install/tools/ipa-csreplica-manage.in +index 6f248cc50f7f81b2014d629355f6f32d1d6ab7be..2fab27a94cfdbef8faadca82bc222bf96d212159 100644 +--- a/install/tools/ipa-csreplica-manage.in ++++ b/install/tools/ipa-csreplica-manage.in +@@ -32,8 +32,8 @@ from ipaserver.install import (replication, installutils, bindinstance, + from ipalib import api, errors + from ipalib.constants import FQDN + from ipalib.util import has_managed_topology, print_replication_status +-from ipapython import ipautil, ipaldap, version +-from ipapython.admintool import ScriptError ++from ipapython import ipautil, ipaldap, version, config ++from ipapython.admintool import admin_cleanup_global_argv, ScriptError + from ipapython.dn import DN + + logger = logging.getLogger(os.path.basename(__file__)) +@@ -54,11 +54,10 @@ commands = { + + + def parse_options(): +- from optparse import OptionParser # pylint: disable=deprecated-module +- +- parser = OptionParser(version=version.VERSION) ++ parser = config.IPAOptionParser(version=version.VERSION) + parser.add_option("-H", "--host", dest="host", help="starting host") +- parser.add_option("-p", "--password", dest="dirman_passwd", help="Directory Manager password") ++ parser.add_option("-p", "--password", dest="dirman_passwd", sensitive=True, ++ help="Directory Manager password") + parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, + help="provide additional information") + parser.add_option("-f", "--force", dest="force", action="store_true", default=False, +@@ -66,6 +65,7 @@ def parse_options(): + parser.add_option("--from", dest="fromhost", help="Host to get data from") + + options, args = parser.parse_args() ++ admin_cleanup_global_argv(parser, options, sys.argv) + + valid_syntax = False + +diff --git a/install/tools/ipa-managed-entries.in b/install/tools/ipa-managed-entries.in +index e3f121943eb3b18ca8f7f8bfeae7813cbc9bd753..ff2fd6a58ccb5b322f75008578fea81f561666fa 100644 +--- a/install/tools/ipa-managed-entries.in ++++ b/install/tools/ipa-managed-entries.in +@@ -24,7 +24,6 @@ import logging + import os + import re + import sys +-from optparse import OptionParser # pylint: disable=deprecated-module + + from ipaplatform.paths import paths + from ipapython import config +@@ -32,6 +31,7 @@ from ipaserver.install import installutils + from ipalib import api, errors + from ipapython.ipa_log_manager import standard_logging_setup + from ipapython.dn import DN ++from ipapython.admintool import admin_cleanup_global_argv + + logger = logging.getLogger(os.path.basename(__file__)) + +@@ -51,9 +51,10 @@ def parse_options(): + action="store_true", + help="List available Managed Entries") + parser.add_option("-p", "--password", dest="dirman_password", +- help="Directory Manager password") ++ sensitive=True, help="Directory Manager password") + + options, args = parser.parse_args() ++ admin_cleanup_global_argv(parser, options, sys.argv) + + return options, args + +diff --git a/install/tools/ipa-replica-conncheck.in b/install/tools/ipa-replica-conncheck.in +index 8eee82483abc275cb37ad96ff272b6ee8192403f..81b7d13ac900031fa81356b894dc3eaaaee0f744 100644 +--- a/install/tools/ipa-replica-conncheck.in ++++ b/install/tools/ipa-replica-conncheck.in +@@ -23,15 +23,15 @@ from __future__ import print_function + import logging + + from ipapython import ipachangeconf +-from ipapython.config import IPAOptionParser ++from ipapython.config import (IPAOptionParser, OptionGroup, ++ OptionValueError) ++from ipapython.admintool import admin_cleanup_global_argv + from ipapython.dn import DN + from ipapython import version + from ipapython import ipautil, certdb + from ipalib import api, errors, x509 + from ipalib.constants import FQDN + from ipaserver.install import installutils +-# pylint: disable=deprecated-module +-from optparse import OptionGroup, OptionValueError + # pylint: enable=deprecated-module + from ipapython.ipa_log_manager import standard_logging_setup + import copy +@@ -189,6 +189,7 @@ def parse_options(): + + options, _args = parser.parse_args() + safe_options = parser.get_safe_opts(options) ++ admin_cleanup_global_argv(parser, options, sys.argv) + + if options.master and options.replica: + parser.error("on-master and on-replica options are mutually exclusive!") +diff --git a/install/tools/ipa-replica-manage.in b/install/tools/ipa-replica-manage.in +index d6e6ef57c39af70f164d41662227af3dc2535f9c..7e5b31a598537f57c471729f22fdec4a5bedc03d 100644 +--- a/install/tools/ipa-replica-manage.in ++++ b/install/tools/ipa-replica-manage.in +@@ -43,6 +43,7 @@ from ipalib.util import ( + print_replication_status, + verify_host_resolvable, + ) ++from ipapython.admintool import admin_cleanup_global_argv + from ipapython.ipa_log_manager import standard_logging_setup + from ipapython.dn import DN + from ipapython.config import IPAOptionParser +@@ -84,7 +85,8 @@ class NoRUVsFound(Exception): + def parse_options(): + parser = IPAOptionParser(version=version.VERSION) + parser.add_option("-H", "--host", dest="host", help="starting host") +- parser.add_option("-p", "--password", dest="dirman_passwd", help="Directory Manager password") ++ parser.add_option("-p", "--password", dest="dirman_passwd", sensitive=True, ++ help="Directory Manager password") + parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, + help="provide additional information") + parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, +@@ -95,7 +97,7 @@ def parse_options(): + help="DANGER: clean up references to a ghost master") + parser.add_option("--binddn", dest="binddn", default=None, type="dn", + help="Bind DN to use with remote server") +- parser.add_option("--bindpw", dest="bindpw", default=None, ++ parser.add_option("--bindpw", dest="bindpw", default=None, sensitive=True, + help="Password for Bind DN to use with remote server") + parser.add_option("--winsync", dest="winsync", action="store_true", default=False, + help="This is a Windows Sync Agreement") +@@ -103,13 +105,15 @@ def parse_options(): + help="Full path and filename of CA certificate to use with TLS/SSL to the remote server") + parser.add_option("--win-subtree", dest="win_subtree", default=None, + help="DN of Windows subtree containing the users you want to sync (default cn=Users, ...', add two args ++ _argc = len(argv) + 2 ++ all_options = [] ++ if '_get_all_options' in dir(option_parser): ++ # OptParse parser ++ all_options = option_parser._get_all_options() ++ elif '_actions' in dir(option_parser): ++ # ArgParse parser ++ all_options = option_parser._actions ++ ++ for opt in all_options: ++ if getattr(opt, 'sensitive', False): ++ v = getattr(options, opt.dest) ++ for i in range(0, _argc): ++ vi = ctypes.cast(_argv[i], ++ ctypes.c_char_p ++ ).value.decode('utf-8') ++ if vi == v: ++ ctypes.memset(_argv[i], ord('X'), len(v)) ++ except Exception: ++ pass ++ ++ + class ScriptError(Exception): + """An exception that records an error message and a return value + """ +@@ -148,6 +187,7 @@ class AdminTool: + cls._option_parsers[cls] = cls.option_parser + + options, args = cls.option_parser.parse_args(argv[1:]) ++ admin_cleanup_global_argv(cls.option_parser, options, argv) + + command_class = cls.get_command_class(options, args) + command = command_class(options, args) +diff --git a/ipaserver/install/ipa_migrate.py b/ipaserver/install/ipa_migrate.py +index f35629378490d3d45ca97f2aa5b4390c67d660ed..ece473bc8cb525e2d563356b5b274502d6b703e8 100644 +--- a/ipaserver/install/ipa_migrate.py ++++ b/ipaserver/install/ipa_migrate.py +@@ -28,6 +28,7 @@ from ipaplatform.paths import paths + from ipapython.dn import DN + from ipapython.ipaldap import LDAPClient, LDAPEntry, realm_to_ldapi_uri + from ipapython.ipa_log_manager import standard_logging_setup ++from ipapython.admintool import admin_cleanup_global_argv + from ipaserver.install.ipa_migrate_constants import ( + DS_CONFIG, DB_OBJECTS, DS_INDEXES, BIND_DN, LOG_FILE_NAME, + STRIP_OP_ATTRS, STRIP_ATTRS, STRIP_OC, PROD_ATTRS, +@@ -284,6 +285,18 @@ class LDIFParser(ldif.LDIFParser): + self.mc.process_db_entry(entry_dn=dn, entry_attrs=entry_attrs) + + ++class SensitiveStoreAction(argparse._StoreAction): ++ def __init__(self, *, sensitive, **options): ++ super(SensitiveStoreAction, self).__init__(**options) ++ self.sensitive = sensitive ++ ++ def _get_kwargs(self): ++ names = super(SensitiveStoreAction, self)._get_kwargs() ++ sensitive_name = 'sensitive' ++ names.extend((sensitive_name, getattr(self, sensitive_name))) ++ return names ++ ++ + # + # Migrate IPA to IPA Class + # +@@ -344,7 +357,8 @@ class IPAMigrate(): + help='Password for the Bind DN. If a password ' + 'is not provided then the user will be ' + 'prompted to enter it', +- default=None) ++ default=None, sensitive=True, ++ action=SensitiveStoreAction) + parser.add_argument('-j', '--bind-pw-file', + help='A text file containing the clear text ' + 'password for the Bind DN', default=None) +@@ -2128,6 +2142,7 @@ class IPAMigrate(): + parser = argparse.ArgumentParser(description=desc, allow_abbrev=True) + self.add_options(parser) + self.validate_options() ++ admin_cleanup_global_argv(parser, self.args, sys.argv) + + # Check for dryrun mode + if self.args.dryrun or self.args.dryrun_record is not None: +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index 8d75a0e6beba09086bc2ce8c73f3bcfe81e52113..539501ab4f0c73571b680aeccf3854b511fd29dc 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -185,7 +185,7 @@ class Restore(admintool.AdminTool): + super(Restore, cls).add_options(parser, debug_option=True) + + parser.add_option( +- "-p", "--password", dest="password", ++ "-p", "--password", dest="password", sensitive=True, + help="Directory Manager password") + parser.add_option( + "--gpg-keyring", dest="gpg_keyring", +diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py +index e9f680b1d1e505f89fc1611b8dbb3f84768f6781..76ad37ca7bcc62364379d56b21ead43c5248f5f1 100644 +--- a/ipaserver/install/ipa_server_certinstall.py ++++ b/ipaserver/install/ipa_server_certinstall.py +@@ -72,7 +72,7 @@ class ServerCertInstall(admintool.AdminTool): + help="Name of the certificate to install") + parser.add_option( + "-p", "--dirman-password", +- dest="dirman_password", ++ dest="dirman_password", sensitive=True, + help="Directory Manager password") + + def validate_options(self): +-- +2.47.1 + diff --git a/0045-ipa-otpd-use-oidc_child-s-client-secret-stdin-option.patch b/0045-ipa-otpd-use-oidc_child-s-client-secret-stdin-option.patch new file mode 100644 index 0000000..a42c3e8 --- /dev/null +++ b/0045-ipa-otpd-use-oidc_child-s-client-secret-stdin-option.patch @@ -0,0 +1,75 @@ +From d857fcfcc21481cdf06b8cce1685e141921d2fbf Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 27 Nov 2024 12:16:09 +0100 +Subject: [PATCH] ipa-otpd: use oidc_child's --client-secret-stdin option + +To remove the client secret from the command line where it would be +visible e.g. when calling ps it is now passed via stdin to oidc_child. + +Fixes: CVE-2024-11029 + +Signed-off-by: Sumit Bose +--- + daemons/ipa-otpd/oauth2.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +diff --git a/daemons/ipa-otpd/oauth2.c b/daemons/ipa-otpd/oauth2.c +index a33cf51715ca2a3e7a0cef871aed5cfbbd037598..52d7d7c9cb6c410bdbaa2e5eddccfea2204d3e69 100644 +--- a/daemons/ipa-otpd/oauth2.c ++++ b/daemons/ipa-otpd/oauth2.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "internal.h" + +@@ -93,6 +94,7 @@ static void oauth2_on_child_writable(verto_ctx *vctx, verto_ev *ev) + (void)vctx; /* Unused */ + ssize_t io; + struct child_ctx *child_ctx; ++ struct iovec iov[3]; + + child_ctx = verto_get_private(ev); + if (child_ctx == NULL) { +@@ -102,15 +104,18 @@ static void oauth2_on_child_writable(verto_ctx *vctx, verto_ev *ev) + } + + if (child_ctx->oauth2_state == OAUTH2_GET_DEVICE_CODE) { +- /* no input needed */ +- verto_del(ev); +- return; +- } +- ++ io = write(verto_get_fd(ev), child_ctx->item->idp.ipaidpClientSecret, ++ strlen(child_ctx->item->idp.ipaidpClientSecret)); ++ } else { ++ iov[0].iov_base = child_ctx->item->idp.ipaidpClientSecret; ++ iov[0].iov_len = strlen(child_ctx->item->idp.ipaidpClientSecret); ++ iov[1].iov_base = "\n"; ++ iov[1].iov_len = 1; ++ iov[2].iov_base = child_ctx->saved_item->oauth2.device_code_reply; ++ iov[2].iov_len = strlen(child_ctx->saved_item->oauth2.device_code_reply); + +- io = write(verto_get_fd(ev), +- child_ctx->saved_item->oauth2.device_code_reply, +- strlen(child_ctx->saved_item->oauth2.device_code_reply)); ++ io = writev(verto_get_fd(ev), iov, 3); ++ } + otpd_queue_item_free(child_ctx->saved_item); + + if (io < 0) { +@@ -429,8 +434,7 @@ int oauth2(struct otpd_queue_item **item, enum oauth2_state oauth2_state) + args[args_idx++] = (*item)->idp.ipaidpClientID; + + if ((*item)->idp.ipaidpClientSecret) { +- args[args_idx++] = "--client-secret"; +- args[args_idx++] = (*item)->idp.ipaidpClientSecret; ++ args[args_idx++] = "--client-secret-stdin"; + } + + if ((*item)->idp.ipaidpScope) { +-- +2.47.1 + diff --git a/0046-Fix-pylint-issue-in-ipatests-i18n.py.patch b/0046-Fix-pylint-issue-in-ipatests-i18n.py.patch new file mode 100644 index 0000000..3e3b822 --- /dev/null +++ b/0046-Fix-pylint-issue-in-ipatests-i18n.py.patch @@ -0,0 +1,69 @@ +From eef544c1d331bbe80852ebe8b5fc9bad0539b6fa Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 15 Jan 2025 15:39:20 +0100 +Subject: [PATCH] Fix pylint issue in ipatests/i18n.py + +This file should not import ipa modules + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rafael Guterres Jeffman +--- + ipatests/i18n.py | 8 ++++---- + pylintrc | 3 ++- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/ipatests/i18n.py b/ipatests/i18n.py +index 57915c286be72124fa23380f97f3922496f00c22..49f5c4c3232346db3147bd7a5ba8056344ac907f 100644 +--- a/ipatests/i18n.py ++++ b/ipatests/i18n.py +@@ -22,6 +22,7 @@ from __future__ import print_function + + # WARNING: Do not import ipa modules, this is also used as a + # stand-alone script (invoked from po Makefile). ++import optparse # pylint: disable=deprecated-module + import sys + import gettext + import re +@@ -29,7 +30,6 @@ import os + import traceback + import polib + from collections import namedtuple +-from ipapython import config + + import six + +@@ -722,9 +722,9 @@ usage =''' + def main(): + global verbose, print_traceback, pedantic, show_strings + +- parser = config.IPAOptionParser(usage=usage) ++ parser = optparse.OptionParser(usage=usage) + +- mode_group = config.OptionGroup(parser, 'Operational Mode', ++ mode_group = optparse.OptionGroup(parser, 'Operational Mode', + 'You must select one these modes to run in') + + mode_group.add_option('-g', '--test-gettext', action='store_const', const='test_gettext', dest='mode', +@@ -748,7 +748,7 @@ def main(): + parser.add_option('--traceback', action='store_true', dest='print_traceback', default=False, + help='print the traceback when an exception occurs') + +- param_group = config.OptionGroup(parser, 'Run Time Parameters', ++ param_group = optparse.OptionGroup(parser, 'Run Time Parameters', + 'These may be used to modify the run time defaults') + + param_group.add_option('--test-lang', action='store', dest='test_lang', default='test', +diff --git a/pylintrc b/pylintrc +index 50278cc76031af68959a138f6ea185c4288c7155..8fadeffbdfdb8013135a17b3493ecc4dc7e5e001 100644 +--- a/pylintrc ++++ b/pylintrc +@@ -153,4 +153,5 @@ forbidden-imports= + ipaplatform/:ipaclient:ipalib:ipaserver, + ipapython/:ipaclient:ipalib:ipaserver + ipatests/pytest_ipa:ipaserver:ipaclient.install:ipalib.install +- ipatests/test_integration:ipaserver ++ ipatests/test_integration:ipaserver, ++ ipatests/i18n.py:ipapython +-- +2.47.1 + diff --git a/freeipa.spec b/freeipa.spec index ac5622b..579bf72 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -224,7 +224,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 7%{?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 @@ -285,6 +285,15 @@ Patch0034: 0034-pyca-adapt-import-paths-for-TripleDES-cipher.patch Patch0035: 0035-ipa-pwd-extop-clarify-OTP-use-over-LDAP-binds.patch Patch0036: 0036-adtrust-add-missing-ipaAllowedOperations-objectclass.patch Patch0037: 0037-Fix-the-typo-in-ipa_migrate_constants.patch +Patch0038: 0038-test_ipahealthcheck-skip-connectivity_and_data-check.patch +Patch0039: 0039-ipatests-Fixes-for-ipa-ipa-migration-tool.patch +Patch0040: 0040-Installation-test-KRA-on-replica-after-cert-renewal.patch +Patch0041: 0041-KRA-cert-renewal-update-ca.connector.KRA.transportCe.patch +Patch0042: 0042-Add-30-second-timeout-for-certmonger-request-start-t.patch +Patch0043: 0043-Unify-use-of-option-parsers.patch +Patch0044: 0044-ipa-tools-remove-sensitive-material-from-the-command.patch +Patch0045: 0045-ipa-otpd-use-oidc_child-s-client-secret-stdin-option.patch +Patch0046: 0046-Fix-pylint-issue-in-ipatests-i18n.py.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -1900,6 +1909,12 @@ fi %endif %changelog +* Thu Jan 16 2025 Florence Blanc-Renaud - 4.12.2-8 +- Resolves: RHEL-73022 A slow HSM can cause IPA server installation to fail setting up certificate tracking [rhel-9] +- Resolves: RHEL-71261 [RHEL-9.6] Include latest fixes in python3-ipatests package +- Resolves: RHEL-67191 CVE-2024-11029 ipa: Administrative user data leaked through systemd journal [rhel-9.6] +- Resolves: RHEL-59040 KRA installation failure caused by a certificate mismatch in NSS DB and configuration file. + * Wed Dec 11 2024 Florence Blanc-Renaud - 4.12.2-7 - Resolves: RHEL-70760 Fix typo in ipa-migrate log file i.e 'Privledges' to 'Privileges' - Resolves: RHEL-70481 ipa-server-upgrade fails after established trust with ad