# # Kickstart module for security. # # Copyright (C) 2018 Red Hat, Inc. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties 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, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. Any Red Hat trademarks that are incorporated in the # source code or documentation are not subject to the GNU General Public # License and may only be used or replicated with the express permission of # Red Hat, Inc. # import shlex from pyanaconda.core.configuration.anaconda import conf from pyanaconda.core.dbus import DBus from pyanaconda.core.kernel import kernel_arguments from pyanaconda.core.signal import Signal from pyanaconda.modules.common.base import KickstartService from pyanaconda.modules.common.constants.services import SECURITY from pyanaconda.modules.common.containers import TaskContainer from pyanaconda.modules.common.structures.realm import RealmData from pyanaconda.modules.common.structures.requirement import Requirement from pyanaconda.modules.security.constants import SELinuxMode from pyanaconda.modules.security.kickstart import SecurityKickstartSpecification from pyanaconda.modules.security.security_interface import SecurityInterface from pyanaconda.modules.security.installation import ConfigureSELinuxTask, \ RealmDiscoverTask, RealmJoinTask, ConfigureAuthselectTask, \ ConfigureFingerprintAuthTask, PreconfigureFIPSTask, ConfigureFIPSTask from pyanaconda.anaconda_loggers import get_module_logger log = get_module_logger(__name__) class SecurityService(KickstartService): """The Security service.""" def __init__(self): super().__init__() self.selinux_changed = Signal() self._selinux = SELinuxMode.DEFAULT self.authselect_changed = Signal() self._authselect_args = [] self.fingerprint_auth_enabled_changed = Signal() self._fingerprint_auth_enabled = False self.realm_changed = Signal() self._realm = RealmData() def publish(self): """Publish the module.""" TaskContainer.set_namespace(SECURITY.namespace) DBus.publish_object(SECURITY.object_path, SecurityInterface(self)) DBus.register_service(SECURITY.service_name) @property def kickstart_specification(self): """Return the kickstart specification.""" return SecurityKickstartSpecification def process_kickstart(self, data): """Process the kickstart data.""" if data.selinux.selinux is not None: self.set_selinux(SELinuxMode(data.selinux.selinux)) if data.authselect.authselect: self.set_authselect(shlex.split(data.authselect.authselect)) if data.realm.join_realm: realm = RealmData() realm.name = data.realm.join_realm realm.discover_options = data.realm.discover_options realm.join_options = data.realm.join_args self.set_realm(realm) def setup_kickstart(self, data): """Set up the kickstart data.""" if self.selinux != SELinuxMode.DEFAULT: data.selinux.selinux = self.selinux.value if self.authselect: data.authselect.authselect = " ".join(self.authselect) if self.realm.name: data.realm.join_realm = self.realm.name data.realm.discover_options = self.realm.discover_options data.realm.join_args = self.realm.join_options @property def fips_enabled(self): """Is FIPS enabled? :return: True or False """ return kernel_arguments.is_enabled("fips") @property def selinux(self): """The state of SELinux on the installed system. :return: an instance of SELinuxMode """ return self._selinux def set_selinux(self, value): """Sets the state of SELinux on the installed system. :param value: an instance of SELinuxMode """ self._selinux = value self.selinux_changed.emit() log.debug("SElinux is set to %s.", value) @property def authselect(self): """Arguments for the authselect tool. :return: a list of arguments """ return self._authselect_args def set_authselect(self, args): """Set the arguments for the authselect tool. :param args: a list of arguments """ self._authselect_args = args self.authselect_changed.emit() log.debug("Authselect is set to %s.", args) @property def fingerprint_auth_enabled(self): """Specifies if fingerprint authentication should be enabled. :return: True if fingerprint authentication should be enabled, False otherwise :rtype: bool """ return self._fingerprint_auth_enabled def set_fingerprint_auth_enabled(self, fingerprint_auth_enabled): """Set if fingerprint authentication should be enabled. :param bool fingerprint_auth_enabled: True if fingerprint authentication should be enabled, False otherwise """ self._fingerprint_auth_enabled = fingerprint_auth_enabled self.fingerprint_auth_enabled_changed.emit() log.debug("Fingerprint authentication enabled is set to %s.", self.fingerprint_auth_enabled) @property def realm(self): """Specification of the enrollment in a realm. :return: an instance of RealmData """ return self._realm def set_realm(self, realm): """Specify of the enrollment in a realm. :param realm: an instance of RealmData """ self._realm = realm self.realm_changed.emit() log.debug("Realm is set to %s.", realm) def handle_realm_discover_results(self, realm_data): """ Handle results from the RealmDiscover task. :param realm_data: an updated instance of realm data """ log.debug("Updating realm data with results from realm discover task.") self.set_realm(realm_data) def collect_requirements(self): """Return installation requirements for this module. :return: a list of requirements """ requirements = [] # Add FIPS requirements. if self.fips_enabled: requirements.append(Requirement.for_package( "/usr/bin/fips-mode-setup", reason="Required for FIPS compliance." )) # Add realm requirements. for name in self.realm.required_packages: requirements.append(Requirement.for_package( name, reason="Needed to join a realm." )) # Add authselect requirements if self.authselect or self.fingerprint_auth_enabled: # we need the authselect package in two cases: # - autselect command is used in kickstart # - to configure fingerprint authentication requirements.append(Requirement.for_package( "authselect", reason="Needed by authselect kickstart command & " "for fingerprint authentication support." )) return requirements def discover_realm_with_task(self): """Return the setup task for discovering a realm.""" realm_task = RealmDiscoverTask(sysroot=conf.target.system_root, realm_data=self.realm) realm_task.succeeded_signal.connect( lambda: self.handle_realm_discover_results(realm_task.get_result()) ) return realm_task def join_realm_with_task(self): """Return the setup task for joining a realm.""" realm_task = RealmJoinTask(sysroot=conf.target.system_root, realm_data=self.realm) # Connect to realm-data-changed signal, so that the realm data in the # realm-join task is always up to date. self.realm_changed.connect(lambda: realm_task.set_realm_data(self.realm)) return realm_task def preconfigure_fips_with_task(self, payload_type): """Set up FIPS for the payload installation with a task. :param payload_type: a string with the payload type :return: an installation task """ return PreconfigureFIPSTask( sysroot=conf.target.system_root, payload_type=payload_type, fips_enabled=self.fips_enabled ) def configure_fips_with_task(self): """Configure FIPS on the installed system. :return: an installation task """ return ConfigureFIPSTask( sysroot=conf.target.system_root, fips_enabled=self.fips_enabled ) def install_with_tasks(self): """Return the installation tasks of this module. :returns: list of installation tasks """ return [ ConfigureSELinuxTask( sysroot=conf.target.system_root, selinux_mode=self.selinux ), ConfigureFingerprintAuthTask( sysroot=conf.target.system_root, fingerprint_auth_enabled=self.fingerprint_auth_enabled ), ConfigureAuthselectTask( sysroot=conf.target.system_root, authselect_options=self.authselect ) ]