From bc03f2abb2924bd22d7e8b4a3c2a5be5ae3e8463 Mon Sep 17 00:00:00 2001 From: Vladimir Slavik Date: Tue, 15 Sep 2020 09:57:58 +0200 Subject: [PATCH 20001/20007] Import RPM certificates at end of installation This adds code and a new config key for importing RPM certificates, and enables it for all of Fedora. Resolves: rhbz#748320 Resolves: rhbz#1858006 (cherry picked from commit 5145db39e88b08eb23ac1b96c1a14f1eb73b2e86) --- data/anaconda.conf | 4 +++ data/product.d/centos-stream.conf | 2 ++ data/product.d/fedora.conf | 4 +++ pyanaconda/core/configuration/payload.py | 5 +++ pyanaconda/core/regexes.py | 3 ++ pyanaconda/core/util.py | 20 ++++++++++++ pyanaconda/payload/dnf/payload.py | 14 +++++++++ tests/nosetests/pyanaconda_tests/util_test.py | 31 +++++++++++++++++++ 8 files changed, 83 insertions(+) diff --git a/data/anaconda.conf b/data/anaconda.conf index 824f4bb56..ab6c15bb6 100644 --- a/data/anaconda.conf +++ b/data/anaconda.conf @@ -97,6 +97,10 @@ check_supported_locales = False # Enable ssl verification for all HTTP connection verify_ssl = True +# GPG keys to import to RPM database by default. +# Specify paths on the installed system, each on a line. +# Substitutions for $releasever and $basearch happen automatically. +default_rpm_gpg_keys = [Security] # Enable SELinux usage in the installed system. diff --git a/data/product.d/centos-stream.conf b/data/product.d/centos-stream.conf index c9eefe8a6..0178bc9e4 100644 --- a/data/product.d/centos-stream.conf +++ b/data/product.d/centos-stream.conf @@ -34,3 +34,5 @@ custom_stylesheet = /usr/share/anaconda/pixmaps/redhat.css [Payload] enable_closest_mirror = True default_source = CLOSEST_MIRROR +default_rpm_gpg_keys = + /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/data/product.d/fedora.conf b/data/product.d/fedora.conf index 0b2eeeeab..31a9245c0 100644 --- a/data/product.d/fedora.conf +++ b/data/product.d/fedora.conf @@ -15,3 +15,7 @@ default_help_pages = fedora_help_placeholder.txt fedora_help_placeholder.xml fedora_help_placeholder.xml + +[Payload] +default_rpm_gpg_keys = + /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch diff --git a/pyanaconda/core/configuration/payload.py b/pyanaconda/core/configuration/payload.py index 5dde92619..4cc2c0244 100644 --- a/pyanaconda/core/configuration/payload.py +++ b/pyanaconda/core/configuration/payload.py @@ -107,3 +107,8 @@ class PayloadSection(Section): this option. """ return self._get_option("verify_ssl", bool) + + @property + def default_rpm_gpg_keys(self): + """List of GPG keys to import into RPM database at end of installation.""" + return self._get_option("default_rpm_gpg_keys", str).split() diff --git a/pyanaconda/core/regexes.py b/pyanaconda/core/regexes.py index ab4cd900b..17d56b752 100644 --- a/pyanaconda/core/regexes.py +++ b/pyanaconda/core/regexes.py @@ -197,3 +197,6 @@ MAC_OCTET = re.compile(r'[a-fA-F0-9][a-fA-F0-9]') # Name of initramfs connection created by NM based on MAC NM_MAC_INITRAMFS_CONNECTION = re.compile(r'^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$') + +# OS version in os-release file +OS_RELEASE_OS_VERSION = re.compile(r"VERSION_ID=[\"']?([0-9a-z._-]+)[\"']?") diff --git a/pyanaconda/core/util.py b/pyanaconda/core/util.py index 825bb7260..16a0f6c6f 100644 --- a/pyanaconda/core/util.py +++ b/pyanaconda/core/util.py @@ -45,6 +45,7 @@ from pyanaconda.core.process_watchers import WatchProcesses from pyanaconda.core.constants import DRACUT_SHUTDOWN_EJECT, TRANSLATIONS_UPDATE_DIR, \ IPMI_ABORTED, X_TIMEOUT, TAINT_HARDWARE_UNSUPPORTED, TAINT_SUPPORT_REMOVED, \ WARNING_HARDWARE_UNSUPPORTED, WARNING_SUPPORT_REMOVED +from pyanaconda.core.regexes import OS_RELEASE_OS_VERSION from pyanaconda.errors import RemovedModuleError from pyanaconda.anaconda_logging import program_log_lock @@ -1469,3 +1470,22 @@ def is_smt_enabled(): except (IOError, ValueError): log.warning("Failed to detect SMT.") return False + + +def get_os_version(sysroot=""): + """Find version of the OS from the os-release file. + + See os-release(5). + + :param str sysroot: Where to look. + :return str: The version + """ + for filename in ("/etc/os-release", "/usr/lib/os-release"): + try: + with open(sysroot + filename, "r") as f: + data = f.read(4096) # 4 kB should be enough for everyone! + return OS_RELEASE_OS_VERSION.findall(data)[0] + except (FileNotFoundError, IndexError): + pass + + return None diff --git a/pyanaconda/payload/dnf/payload.py b/pyanaconda/payload/dnf/payload.py index 47e00a49b..ac717e793 100644 --- a/pyanaconda/payload/dnf/payload.py +++ b/pyanaconda/payload/dnf/payload.py @@ -2037,6 +2037,17 @@ class DNFPayload(Payload): """Should we write the storage before doing the installation?""" return True + def _import_rpm_keys(self): + """Import GPG keys to RPM database.""" + if conf.payload.default_rpm_gpg_keys: + # TODO: replace the interpolation with DNF once possible + arch = util.execWithCapture("uname", ["-i"]).strip().replace("'", "") + vers = util.get_os_version(conf.target.system_root) + for key in conf.payload.default_rpm_gpg_keys: + interpolated_key = key.replace("$releasever", vers).replace("$basearch", arch) + log.info("Importing GPG key to RPM database: %s", interpolated_key) + util.execInSysroot("rpm", ["--import", interpolated_key]) + def post_setup(self): """Perform post-setup tasks. @@ -2076,6 +2087,9 @@ class DNFPayload(Payload): self._base.close() super().post_install() + # rpm needs importing installed certificates manually, see rhbz#748320 and rhbz#185800 + self._import_rpm_keys() + @property def kernel_version_list(self): # Find all installed rpms that provide 'kernel' diff --git a/tests/nosetests/pyanaconda_tests/util_test.py b/tests/nosetests/pyanaconda_tests/util_test.py index f047a1e66..c2c3c0c0f 100644 --- a/tests/nosetests/pyanaconda_tests/util_test.py +++ b/tests/nosetests/pyanaconda_tests/util_test.py @@ -855,3 +855,34 @@ class MiscTests(unittest.TestCase): ) self.assertEqual(get_anaconda_version_string(), "1.0") self.assertEqual(get_anaconda_version_string(build_time_version=True), "1.0-1") + + def get_os_version_test(self): + """Test get_os_version.""" + with tempfile.TemporaryDirectory() as root: + # prepare paths + util.mkdirChain(root + "/usr/lib") + util.mkdirChain(root + "/etc") + + # backup file only + with open(root + "/usr/lib/os-release", "w") as f: + f.write("# blah\nVERSION_ID=foo256bar \n VERSION_ID = wrong\n\n") + version = util.get_os_version(root) + self.assertEqual(version, "foo256bar") + + # main file and backup too + with open(root + "/etc/os-release", "w") as f: + f.write("# blah\nVERSION_ID=more-important\n") + version = util.get_os_version(root) + self.assertEqual(version, "more-important") + + # both, main file twice + with open(root + "/etc/os-release", "w") as f: + f.write("# blah\nVERSION_ID=more-important\nVERSION_ID=not-reached\n \n") + version = util.get_os_version(root) + self.assertEqual(version, "more-important") + + # no files + os.remove(root + "/usr/lib/os-release") + os.remove(root + "/etc/os-release") + version = util.get_os_version(root) + self.assertEqual(version, None) -- 2.31.1