Blob Blame History Raw
From 5e7a6e648c85cf923093ebac6448be82ba032448 Mon Sep 17 00:00:00 2001
From: Vratislav Podzimek <vpodzime@redhat.com>
Date: Wed, 25 May 2016 10:58:54 +0200
Subject: [PATCH 06/13] Allow fixing root password in graphical installations

If the root password from kickstart is too short we can give users a chance to
enter a new (better) one in case of graphical installation. Text mode doesn't
allow for this because the root password configuration happens before the SCAP
content is evaluated.

Resolves: rhbz#1265116
---
 org_fedora_oscap/common.py           |  3 ++-
 org_fedora_oscap/gui/spokes/oscap.py | 39 +++++++++++++++++++++++++++++++-----
 org_fedora_oscap/rule_handling.py    | 29 ++++++++++++++++-----------
 3 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/org_fedora_oscap/common.py b/org_fedora_oscap/common.py
index d09ccbd..8b2e84f 100644
--- a/org_fedora_oscap/common.py
+++ b/org_fedora_oscap/common.py
@@ -82,9 +82,10 @@ MESSAGE_TYPE_WARNING = 1
 MESSAGE_TYPE_INFO = 2
 
 # namedtuple for messages returned from the rules evaluation
+#   origin -- class (inherited from RuleHandler) that generated the message
 #   type -- one of the MESSAGE_TYPE_* constants defined above
 #   text -- the actual message that should be displayed, logged, ...
-RuleMessage = namedtuple("RuleMessage", ["type", "text"])
+RuleMessage = namedtuple("RuleMessage", ["origin", "type", "text"])
 
 def get_fix_rules_pre(profile, fpath, ds_id="", xccdf_id="", tailoring=""):
     """
diff --git a/org_fedora_oscap/gui/spokes/oscap.py b/org_fedora_oscap/gui/spokes/oscap.py
index 3b8dbd7..42fc406 100644
--- a/org_fedora_oscap/gui/spokes/oscap.py
+++ b/org_fedora_oscap/gui/spokes/oscap.py
@@ -200,6 +200,11 @@ class OSCAPSpoke(NormalSpoke):
         # leaving the spoke
         self._rule_data = None
 
+        # used for storing previously set root password if we need to remove it
+        # due to the chosen policy (so that we can put it back in case of
+        # revert)
+        self.__old_root_pw = None
+
         # used to check if the profile was changed or not
         self._active_profile = None
 
@@ -584,20 +589,43 @@ class OSCAPSpoke(NormalSpoke):
             # no messages from the rules, add a message informing about that
             if not self._active_profile:
                 # because of no profile
-                message = common.RuleMessage(common.MESSAGE_TYPE_INFO,
-                                           _("No profile selected"))
+                message = common.RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO,
+                                             _("No profile selected"))
             else:
                 # because of no pre-inst rules
-                message = common.RuleMessage(common.MESSAGE_TYPE_INFO,
-                              _("No rules for the pre-installation phase"))
+                message = common.RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO,
+                                             _("No rules for the pre-installation phase"))
             self._add_message(message)
 
             # nothing more to be done
             return
 
+        self._resolve_rootpw_issues(messages, report_only)
         for msg in messages:
             self._add_message(msg)
 
+    def _resolve_rootpw_issues(self, messages, report_only):
+        """Mitigate root password issues (which are not fatal in GUI)"""
+        fatal_rootpw_msgs = [msg for msg in messages
+                             if msg.origin == rule_handling.PasswdRules and msg.type == common.MESSAGE_TYPE_FATAL]
+        if fatal_rootpw_msgs:
+            for msg in fatal_rootpw_msgs:
+                # cannot just change the message type because it is a namedtuple
+                messages.remove(msg)
+                messages.append(common.RuleMessage(self.__class__, common.MESSAGE_TYPE_WARNING, msg.text))
+            if not report_only:
+                self.__old_root_pw = self.data.rootpw.password
+                self.data.rootpw.password = None
+                self.__old_root_pw_seen = self.data.rootpw.password.seen
+                self.data.rootpw.password.seen = False
+
+    def _revert_rootpw_changes(self):
+        if self.__old_root_pw is not None:
+            self.data.rootpw.password = self.__old_root_pw
+            self.data.rootpw.password.seen = self.__old_root_pw_seen
+            self.__old_root_pw = None
+            self.__old_root_pw_seen = None
+
     @gtk_action_wait
     def _unselect_profile(self, profile_id):
         """Unselects the given profile."""
@@ -615,6 +643,7 @@ class OSCAPSpoke(NormalSpoke):
         if self._rule_data:
             # revert changes and clear rule_data (no longer valid)
             self._rule_data.revert_changes(self.data, self._storage)
+            self._revert_rootpw_changes()
             self._rule_data = None
 
         self._active_profile = None
@@ -769,7 +798,7 @@ class OSCAPSpoke(NormalSpoke):
 
             # no messages in the dry-run mode
             self._message_store.clear()
-            message = common.RuleMessage(common.MESSAGE_TYPE_INFO,
+            message = common.RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO,
                                          _("Not applying security policy"))
             self._add_message(message)
 
diff --git a/org_fedora_oscap/rule_handling.py b/org_fedora_oscap/rule_handling.py
index a7bed22..2d58efe 100644
--- a/org_fedora_oscap/rule_handling.py
+++ b/org_fedora_oscap/rule_handling.py
@@ -223,6 +223,11 @@ class RuleData(RuleHandler):
         if opts.passwd:
             self._bootloader_rules.require_password()
 
+    @property
+    def passwd_rules(self):
+        # needed for fixups in GUI
+        return self._passwd_rules
+
 class PartRules(RuleHandler):
     """Simple class holding data from the rules affecting partitioning."""
 
@@ -324,7 +329,7 @@ class PartRule(RuleHandler):
         if self._mount_point not in storage.mountpoints:
             msg = _("%s must be on a separate partition or logical "
                     "volume" % self._mount_point)
-            messages.append(RuleMessage(common.MESSAGE_TYPE_FATAL, msg))
+            messages.append(RuleMessage(self.__class__, common.MESSAGE_TYPE_FATAL, msg))
 
             # mount point doesn't exist, nothing more can be found here
             return messages
@@ -337,7 +342,7 @@ class PartRule(RuleHandler):
         for opt in self._added_mount_options:
             msg = msg_tmpl % { "mount_option": opt,
                                "mount_point": self._mount_point }
-            messages.append(RuleMessage(common.MESSAGE_TYPE_INFO, msg))
+            messages.append(RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO, msg))
 
         # mount point to be created during installation
         target_mount_point = storage.mountpoints[self._mount_point]
@@ -352,7 +357,7 @@ class PartRule(RuleHandler):
                                "mount_point": self._mount_point }
 
             # add message for the mount option in any case
-            messages.append(RuleMessage(common.MESSAGE_TYPE_INFO, msg))
+            messages.append(RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO, msg))
 
             # add new options to the target mount point if not reporting only
             if not report_only:
@@ -428,18 +433,18 @@ class PasswdRules(RuleHandler):
 
             msg = _("make sure to create password with minimal length of %d "
                     "characters") % self._minlen
-            ret = [RuleMessage(common.MESSAGE_TYPE_WARNING, msg)]
+            ret = [RuleMessage(self.__class__, common.MESSAGE_TYPE_WARNING, msg)]
         else:
             # root password set
             if ksdata.rootpw.isCrypted:
                 msg = _("cannot check root password length (password is crypted)")
                 log.warning("cannot check root password length (password is crypted)")
-                return [RuleMessage(common.MESSAGE_TYPE_WARNING, msg)]
+                return [RuleMessage(self.__class__, common.MESSAGE_TYPE_WARNING, msg)]
             elif len(ksdata.rootpw.password) < self._minlen:
                 # too short
                 msg = _("root password is too short, a longer one with at "
                         "least %d characters is required") % self._minlen
-                ret = [RuleMessage(common.MESSAGE_TYPE_FATAL, msg)]
+                ret = [RuleMessage(self.__class__, common.MESSAGE_TYPE_FATAL, msg)]
             else:
                 ret = []
 
@@ -532,7 +537,7 @@ class PackageRules(RuleHandler):
         for pkg in self._added_pkgs:
             msg = _("package '%s' has been added to the list of to be installed "
                     "packages" % pkg)
-            messages.append(RuleMessage(common.MESSAGE_TYPE_INFO, msg))
+            messages.append(RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO, msg))
 
         # packages, that should be added
         packages_to_add = (pkg for pkg in self._add_pkgs
@@ -546,7 +551,7 @@ class PackageRules(RuleHandler):
 
             msg = _("package '%s' has been added to the list of to be installed "
                     "packages" % pkg)
-            messages.append(RuleMessage(common.MESSAGE_TYPE_INFO, msg))
+            messages.append(RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO, msg))
 
         ### now do the same for the packages that should be excluded
 
@@ -554,7 +559,7 @@ class PackageRules(RuleHandler):
         for pkg in self._removed_pkgs:
             msg = _("package '%s' has been added to the list of excluded "
                     "packages" % pkg)
-            messages.append(RuleMessage(common.MESSAGE_TYPE_INFO, msg))
+            messages.append(RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO, msg))
 
         # packages, that should be added
         packages_to_remove = (pkg for pkg in self._remove_pkgs
@@ -568,7 +573,7 @@ class PackageRules(RuleHandler):
 
             msg = _("package '%s' has been added to the list of excluded "
                     "packages" % pkg)
-            messages.append(RuleMessage(common.MESSAGE_TYPE_INFO, msg))
+            messages.append(RuleMessage(self.__class__, common.MESSAGE_TYPE_INFO, msg))
 
         return messages
 
@@ -618,8 +623,8 @@ class BootloaderRules(RuleHandler):
             # Anaconda doesn't provide a way to set bootloader password, so
             # users cannot do much about that --> we shouldn't stop the
             # installation, should we?
-            return [RuleMessage(common.MESSAGE_TYPE_WARNING,
-                               "boot loader password not set up")]
+            return [RuleMessage(self.__class__, common.MESSAGE_TYPE_WARNING,
+                                "boot loader password not set up")]
         else:
             return []
 
-- 
2.5.5