Blame SOURCES/0022-Allow-multiple-file-modes-in-the-FileChecker.patch

45cc94
From 96a780d75274031fd97167c1109fcb63efa7d5cd Mon Sep 17 00:00:00 2001
45cc94
From: Rob Crittenden <rcritten@redhat.com>
45cc94
Date: Tue, 5 Apr 2022 09:25:45 -0400
45cc94
Subject: [PATCH] Allow multiple file modes in the FileChecker
45cc94
45cc94
There are some cases where a strict file mode is not
45cc94
necessary. The kadmind.log is one.
45cc94
45cc94
It is owned root:root so there is no real difference
45cc94
between 0600 and 0640. So allow both.
45cc94
45cc94
https://bugzilla.redhat.com/show_bug.cgi?id=2058239
45cc94
45cc94
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
45cc94
---
45cc94
 src/ipahealthcheck/core/files.py | 31 +++++++++++++++++++++++--------
45cc94
 src/ipahealthcheck/ipa/files.py  |  3 ++-
45cc94
 tests/test_core_files.py         | 32 ++++++++++++++++++++++++++++----
45cc94
 3 files changed, 53 insertions(+), 13 deletions(-)
45cc94
45cc94
diff --git a/src/ipahealthcheck/core/files.py b/src/ipahealthcheck/core/files.py
45cc94
index 1b208d1..af03243 100644
45cc94
--- a/src/ipahealthcheck/core/files.py
45cc94
+++ b/src/ipahealthcheck/core/files.py
45cc94
@@ -16,13 +16,15 @@ class FileCheck:
45cc94
        files is a tuple of tuples. Each tuple consists of:
45cc94
            (path, expected_perm, expected_owner, expected_group)
45cc94
 
45cc94
-       perm is in the form of a POSIX ACL: e.g. 0440, 0770.
45cc94
+       perm is a POSIX ACL as either a string or tuple: e.g. 0440, (0770,).
45cc94
        Owner and group are names, not uid/gid.
45cc94
     """
45cc94
 
45cc94
     @duration
45cc94
     def check(self):
45cc94
         for (path, owner, group, mode) in self.files:
45cc94
+            if not isinstance(mode, tuple):
45cc94
+                mode = tuple((mode,))
45cc94
             if not os.path.exists(path):
45cc94
                 for type in ('mode', 'owner', 'group'):
45cc94
                     key = '%s_%s' % (path.replace('/', '_'), type)
45cc94
@@ -33,19 +35,32 @@ class FileCheck:
45cc94
             stat = os.stat(path)
45cc94
             fmode = str(oct(stat.st_mode)[-4:])
45cc94
             key = '%s_mode' % path.replace('/', '_')
45cc94
-            if mode != fmode:
45cc94
-                if mode < fmode:
45cc94
+            if fmode not in mode:
45cc94
+                if len(mode) == 1:
45cc94
+                    modes = mode[0]
45cc94
+                else:
45cc94
+                    modes = 'one of {}'.format(','.join(mode))
45cc94
+                if all(m < fmode for m in mode):
45cc94
                     yield Result(self, constants.WARNING, key=key,
45cc94
-                                 path=path, type='mode', expected=mode,
45cc94
+                                 path=path, type='mode', expected=modes,
45cc94
                                  got=fmode,
45cc94
                                  msg='Permissions of %s are too permissive: '
45cc94
-                                 '%s and should be %s' % (path, fmode, mode))
45cc94
-                if mode > fmode:
45cc94
+                                 '%s and should be %s' %
45cc94
+                                 (path, fmode, modes))
45cc94
+                elif all(m > fmode for m in mode):
45cc94
                     yield Result(self, constants.ERROR, key=key,
45cc94
-                                 path=path, type='mode', expected=mode,
45cc94
+                                 path=path, type='mode', expected=modes,
45cc94
                                  got=fmode,
45cc94
                                  msg='Permissions of %s are too restrictive: '
45cc94
-                                 '%s and should be %s' % (path, fmode, mode))
45cc94
+                                 '%s and should be %s' %
45cc94
+                                 (path, fmode, modes))
45cc94
+                else:
45cc94
+                    yield Result(self, constants.ERROR, key=key,
45cc94
+                                 path=path, type='mode', expected=modes,
45cc94
+                                 got=fmode,
45cc94
+                                 msg='Permissions of %s are unexpected: '
45cc94
+                                 '%s and should be %s' %
45cc94
+                                 (path, fmode, modes))
45cc94
             else:
45cc94
                 yield Result(self, constants.SUCCESS, key=key,
45cc94
                              type='mode', path=path)
45cc94
diff --git a/src/ipahealthcheck/ipa/files.py b/src/ipahealthcheck/ipa/files.py
45cc94
index abfa52f..a372992 100644
45cc94
--- a/src/ipahealthcheck/ipa/files.py
45cc94
+++ b/src/ipahealthcheck/ipa/files.py
45cc94
@@ -118,7 +118,8 @@ class IPAFileCheck(IPAPlugin, FileCheck):
45cc94
         self.files.append((paths.IPA_CUSTODIA_AUDIT_LOG,
45cc94
                           'root', 'root', '0644'))
45cc94
 
45cc94
-        self.files.append((paths.KADMIND_LOG, 'root', 'root', '0600'))
45cc94
+        self.files.append((paths.KADMIND_LOG, 'root', 'root',
45cc94
+                          ('0600', '0640')))
45cc94
         self.files.append((paths.KRB5KDC_LOG, 'root', 'root', '0640'))
45cc94
 
45cc94
         inst = api.env.realm.replace('.', '-')
45cc94
diff --git a/tests/test_core_files.py b/tests/test_core_files.py
45cc94
index 8257f40..509e28e 100644
45cc94
--- a/tests/test_core_files.py
45cc94
+++ b/tests/test_core_files.py
45cc94
@@ -15,7 +15,8 @@ nobody = pwd.getpwnam('nobody')
45cc94
 
45cc94
 # Mock files to test
45cc94
 files = (('foo', 'root', 'root', '0660'),
45cc94
-         ('bar', 'nobody', 'nobody', '0664'),)
45cc94
+         ('bar', 'nobody', 'nobody', '0664'),
45cc94
+         ('zap', 'root', 'root', ('0664', '0640'),))
45cc94
 
45cc94
 
45cc94
 def make_stat(mode=33200, uid=0, gid=0):
45cc94
@@ -25,6 +26,13 @@ def make_stat(mode=33200, uid=0, gid=0):
45cc94
             mode = 0660
45cc94
             owner = root
45cc94
             group = root
45cc94
+
45cc94
+       Cheat sheet equivalents:
45cc94
+           0600 = 33152
45cc94
+           0640 = 33184
45cc94
+           0644 = 33188
45cc94
+           0660 = 33200
45cc94
+           0666 = 33206
45cc94
     """
45cc94
     return posix.stat_result((mode, 1, 42, 1, uid, gid, 0, 1, 1, 1,))
45cc94
 
45cc94
@@ -80,6 +88,11 @@ def test_files_group(mock_stat):
45cc94
     assert my_results.results[0].result == constants.WARNING
45cc94
     assert my_results.results[1].result == constants.SUCCESS
45cc94
 
45cc94
+    assert my_results.results[2].result == constants.WARNING
45cc94
+    assert my_results.results[2].kw.get('got') == 'nobody'
45cc94
+    assert my_results.results[2].kw.get('expected') == 'root'
45cc94
+    assert my_results.results[2].kw.get('type') == 'group'
45cc94
+
45cc94
 
45cc94
 @patch('os.stat')
45cc94
 def test_files_mode(mock_stat):
45cc94
@@ -94,17 +107,28 @@ def test_files_mode(mock_stat):
45cc94
     assert my_results.results[0].result == constants.SUCCESS
45cc94
     assert my_results.results[1].result == constants.ERROR
45cc94
 
45cc94
-    mock_stat.return_value = make_stat(mode=33152)
45cc94
+    mock_stat.return_value = make_stat(mode=33152)  # 0600
45cc94
     results = capture_results(f)
45cc94
     my_results = get_results(results, 'mode')
45cc94
     assert my_results.results[0].result == constants.ERROR
45cc94
     assert my_results.results[1].result == constants.ERROR
45cc94
+    assert my_results.results[2].result == constants.ERROR
45cc94
 
45cc94
-    mock_stat.return_value = make_stat(mode=33206)
45cc94
+    # Too restrictive
45cc94
+    mock_stat.return_value = make_stat(mode=33206)  # 0666
45cc94
     results = capture_results(f)
45cc94
     my_results = get_results(results, 'mode')
45cc94
     assert my_results.results[0].result == constants.WARNING
45cc94
     assert my_results.results[1].result == constants.WARNING
45cc94
+    assert my_results.results[2].result == constants.WARNING
45cc94
+
45cc94
+    # Too restrictive with allowed multi-mode value
45cc94
+    mock_stat.return_value = make_stat(mode=33184)  # 0640
45cc94
+    results = capture_results(f)
45cc94
+    my_results = get_results(results, 'mode')
45cc94
+    assert my_results.results[0].result == constants.ERROR
45cc94
+    assert my_results.results[1].result == constants.ERROR
45cc94
+    assert my_results.results[2].result == constants.SUCCESS
45cc94
 
45cc94
 
45cc94
 @patch('os.path.exists')
45cc94
@@ -118,7 +142,7 @@ def test_files_not_found(mock_exists):
45cc94
 
45cc94
     for type in ('mode', 'group', 'owner'):
45cc94
         my_results = get_results(results, type)
45cc94
-        assert len(my_results.results) == 2
45cc94
+        assert len(my_results.results) == len(f.files)
45cc94
         for result in my_results.results:
45cc94
             assert result.result == constants.SUCCESS
45cc94
             assert result.kw.get('msg') == 'File does not exist'
45cc94
-- 
45cc94
2.31.1
45cc94