Blob Blame History Raw
From 4ebcf9d422bef11bd5b50f421a4b30ed826d1cbb Mon Sep 17 00:00:00 2001
From: Vladimir Slavik <vslavik@redhat.com>
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 723a48403..c8af2d2fe 100644
--- a/data/product.d/centos-stream.conf
+++ b/data/product.d/centos-stream.conf
@@ -32,3 +32,5 @@ default_help_pages =
 [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 6fab33ed5..73c9d5ba3 100644
--- a/pyanaconda/core/util.py
+++ b/pyanaconda/core/util.py
@@ -47,6 +47,7 @@ from pyanaconda.core.constants import DRACUT_SHUTDOWN_EJECT, TRANSLATIONS_UPDATE
     IPMI_ABORTED, X_TIMEOUT, TAINT_HARDWARE_UNSUPPORTED, TAINT_SUPPORT_REMOVED, \
     WARNING_HARDWARE_UNSUPPORTED, WARNING_SUPPORT_REMOVED
 from pyanaconda.core.constants import SCREENSHOTS_DIRECTORY, SCREENSHOTS_TARGET_DIRECTORY
+from pyanaconda.core.regexes import OS_RELEASE_OS_VERSION
 from pyanaconda.errors import RemovedModuleError
 
 from pyanaconda.anaconda_logging import program_log_lock
@@ -1489,3 +1490,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