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