[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Mon Jul 31 10:56:01 UTC 2023


The branch, master has been updated
       via  16eaf7fd52e gp: Cleanup some unused code
       via  ab2cda79280 gp: Ensure centrify crontab user policy performs proper cleanup
       via  8cc706c1025 gp: Ensure script user policy performs proper cleanup
       via  b278f15890a gp: Ensure smb.conf policy preforms proper cleanup
       via  a330ad7b2cc gp: Ensure MOTD policy preforms proper cleanup
       via  8bdb1b65332 gp: Ensure Issue policy preforms proper cleanup
       via  8a24829093e gp: Ensure Messages policy preforms proper cleanup
       via  03d796c6778 gp: Ensure Firefox policy preforms proper cleanup
       via  8f59ce543a8 gp: Add a misc applier, to assist some gp exts
       via  6ac22de7493 gp: Ensure Firewalld preforms proper cleanup
       via  7db3b63e769 gp: Test modifying centrify crontab user policy enforces changes
       via  70d3601fc64 gp: Test modifying script user policy enforces changes
       via  5c2dc0cce46 gp: Test modifying smb.conf policy enforces changes
       via  c5571718006 gp: Test modifying Issue policy enforces changes
       via  ae752b8c0b3 gp: Test modifying Messages policy enforces changes
       via  ef0c54d7c24 gp: Test modifying MOTD policy enforces changes
       via  32a70df7e4e gp: Test modifying firefox policy enforces changes
       via  b49d150db9a gp: Test modifying firewalld policy enforces changes
       via  217beca6e9d gp: Ensure Firewalld tests don't flop
      from  5571ce9619d dsdb: Use samdb_system_container_dn() in pdb_samba_dsdb_*()

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 16eaf7fd52e91ed8cfb39ac98e6d9bf470bfc358
Author: David Mulder <dmulder at samba.org>
Date:   Tue Jan 10 10:07:33 2023 -0700

    gp: Cleanup some unused code
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Mon Jul 31 10:55:26 UTC 2023 on atb-devel-224

commit ab2cda79280e3a3ce4b806f96a5896d2a463b5ea
Author: David Mulder <dmulder at samba.org>
Date:   Tue Jul 25 13:23:10 2023 -0600

    gp: Ensure centrify crontab user policy performs proper cleanup
    
    This resolves cleanup issues for user and group
    centrify compatible policies. It also ensures the
    crontab policies use functions from the scripts
    policy, to avoid code duplication and simplify
    cleanup.
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8cc706c1025ec521f7f878bba8a48e6d66750fe0
Author: David Mulder <dmulder at samba.org>
Date:   Tue Jan 10 13:21:49 2023 -0700

    gp: Ensure script user policy performs proper cleanup
    
    This resolves cleanup issues for scripts user
    policy.
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b278f15890a3625f2b1663ea543e032ef411fac1
Author: David Mulder <dmulder at samba.org>
Date:   Tue Jan 10 09:57:21 2023 -0700

    gp: Ensure smb.conf policy preforms proper cleanup
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit a330ad7b2cc163f34eb2d379e6ef98e7e449d477
Author: David Mulder <dmulder at samba.org>
Date:   Mon Jan 9 17:19:44 2023 -0700

    gp: Ensure MOTD policy preforms proper cleanup
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8bdb1b65332342da4d28af3b9d9fbcfca15a869e
Author: David Mulder <dmulder at samba.org>
Date:   Mon Jan 9 17:12:53 2023 -0700

    gp: Ensure Issue policy preforms proper cleanup
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8a24829093ef234a5044fab1e9f9992a41e29be1
Author: David Mulder <dmulder at samba.org>
Date:   Mon Jan 9 16:33:59 2023 -0700

    gp: Ensure Messages policy preforms proper cleanup
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 03d796c6778e1499b0a753ffd371d0437c9a27f8
Author: David Mulder <dmulder at samba.org>
Date:   Mon Jan 9 15:20:57 2023 -0700

    gp: Ensure Firefox policy preforms proper cleanup
    
    Now uses gp_misc_applier to ensure old settings
    are properly cleaned up.
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8f59ce543a88607ca244c1982238f4d01e173a4c
Author: David Mulder <dmulder at samba.org>
Date:   Mon Jan 9 15:19:48 2023 -0700

    gp: Add a misc applier, to assist some gp exts
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 6ac22de74938862b489e29090f4e6ec17c643dd8
Author: David Mulder <dmulder at samba.org>
Date:   Fri Jan 6 14:48:12 2023 -0700

    gp: Ensure Firewalld preforms proper cleanup
    
    Now uses gp_applier to ensure old settings are
    properly cleaned up.
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 7db3b63e769baa7d485e12556351bf4533987c8e
Author: David Mulder <dmulder at samba.org>
Date:   Tue Jul 25 13:48:25 2023 -0600

    gp: Test modifying centrify crontab user policy enforces changes
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 70d3601fc648813b05ed2ec08da4c78229023763
Author: David Mulder <dmulder at samba.org>
Date:   Tue Jul 25 13:41:06 2023 -0600

    gp: Test modifying script user policy enforces changes
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 5c2dc0cce4670091856885df26fd4e64fa4ba2d6
Author: David Mulder <dmulder at samba.org>
Date:   Fri Feb 10 14:12:03 2023 -0700

    gp: Test modifying smb.conf policy enforces changes
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c55717180062afd5a5af1fc07adb11b428609af0
Author: David Mulder <dmulder at samba.org>
Date:   Fri Feb 10 13:55:13 2023 -0700

    gp: Test modifying Issue policy enforces changes
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit ae752b8c0b3fb5abc292bd9f040dea1b187510f1
Author: David Mulder <dmulder at samba.org>
Date:   Tue Jul 25 12:52:11 2023 -0600

    gp: Test modifying Messages policy enforces changes
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit ef0c54d7c2408c4c51678419173c064844671651
Author: David Mulder <dmulder at samba.org>
Date:   Fri Feb 10 13:04:16 2023 -0700

    gp: Test modifying MOTD policy enforces changes
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 32a70df7e4efac12573e3a4cbf5a15a7c6d4a151
Author: David Mulder <dmulder at samba.org>
Date:   Thu Feb 9 15:27:00 2023 -0700

    gp: Test modifying firefox policy enforces changes
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b49d150db9aca415f8473f785291c4c87300416e
Author: David Mulder <dmulder at samba.org>
Date:   Fri Jan 13 11:15:50 2023 -0700

    gp: Test modifying firewalld policy enforces changes
    
    Ensure that modifying the firewalld policy and
    re-applying will enforce the correct policy.
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 217beca6e9dc68db774e79ade59b4f7d4c3791b7
Author: David Mulder <dmulder at samba.org>
Date:   Fri Jan 6 14:49:19 2023 -0700

    gp: Ensure Firewalld tests don't flop
    
    This test was failing depending on the system it
    was run on, since the result depends on whether
    firewalld python bindings were installed. This
    wasn't failing in CI (and so there is no flopping
    test marked), but does fail on some local systems.
    
    Signed-off-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 python/samba/gp/gp_centrify_crontab_ext.py |  75 +++----
 python/samba/gp/gp_firefox_ext.py          | 139 ++++++++----
 python/samba/gp/gp_firewalld_ext.py        |  74 ++++---
 python/samba/gp/gp_msgs_ext.py             |  74 ++++---
 python/samba/gp/gp_scripts_ext.py          |  64 +++---
 python/samba/gp/gp_smb_conf_ext.py         |  77 ++++---
 python/samba/gp/gpclass.py                 |  27 +++
 python/samba/gp/vgp_files_ext.py           |   1 -
 python/samba/gp/vgp_issue_ext.py           |  47 +++--
 python/samba/gp/vgp_motd_ext.py            |  47 +++--
 python/samba/gp/vgp_startup_scripts_ext.py |   1 -
 python/samba/tests/bin/firewall-cmd        |  12 +-
 python/samba/tests/gpo.py                  | 329 ++++++++++++++++++++++++++---
 13 files changed, 686 insertions(+), 281 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/gp/gp_centrify_crontab_ext.py b/python/samba/gp/gp_centrify_crontab_ext.py
index e8ffd8bec9f..e532416d224 100644
--- a/python/samba/gp/gp_centrify_crontab_ext.py
+++ b/python/samba/gp/gp_centrify_crontab_ext.py
@@ -16,9 +16,11 @@
 
 import os, re
 from subprocess import Popen, PIPE
-from samba.gp.gpclass import gp_pol_ext, drop_privileges, gp_file_applier
-from hashlib import blake2b
+from samba.gp.gpclass import gp_pol_ext, drop_privileges, gp_file_applier, \
+    gp_misc_applier
 from tempfile import NamedTemporaryFile
+from samba.gp.gp_scripts_ext import fetch_crontab, install_crontab, \
+    install_user_crontab
 
 intro = '''
 ### autogenerated by samba
@@ -92,73 +94,44 @@ class gp_centrify_crontab_ext(gp_pol_ext, gp_file_applier):
                     output[str(self)].append(e.data)
         return output
 
-def fetch_crontab(username):
-    p = Popen(['crontab', '-l', '-u', username], stdout=PIPE, stderr=PIPE)
-    out, err = p.communicate()
-    if p.returncode != 0:
-        raise RuntimeError('Failed to read the crontab: %s' % err)
-    m = re.findall('%s(.*)%s' % (intro, end), out.decode(), re.DOTALL)
-    if len(m) == 1:
-        entries = m[0].strip().split('\n')
-    else:
-        entries = []
-    m = re.findall('(.*)%s.*%s(.*)' % (intro, end), out.decode(), re.DOTALL)
-    if len(m) == 1:
-        others = '\n'.join([l.strip() for l in m[0]])
-    else:
-        others = out.decode()
-    return others, entries
+class gp_user_centrify_crontab_ext(gp_centrify_crontab_ext, gp_misc_applier):
+    def unapply(self, guid, attribute, entry):
+        others, entries = fetch_crontab(self.username)
+        if entry in entries:
+            entries.remove(entry)
+            install_user_crontab(self.username, others, entries)
+        self.cache_remove_attribute(guid, attribute)
 
-def install_crontab(fname, username):
-    p = Popen(['crontab', fname, '-u', username], stdout=PIPE, stderr=PIPE)
-    _, err = p.communicate()
-    if p.returncode != 0:
-        raise RuntimeError('Failed to install crontab: %s' % err)
+    def apply(self, guid, attribute, entry):
+        old_val = self.cache_get_attribute_value(guid, attribute)
+        others, entries = fetch_crontab(self.username)
+        if not old_val or entry not in entries:
+            entries.append(entry)
+            install_user_crontab(self.username, others, entries)
+            self.cache_add_attribute(guid, attribute, entry)
 
-class gp_user_centrify_crontab_ext(gp_centrify_crontab_ext):
     def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
         for guid, settings in deleted_gpo_list:
-            self.gp_db.set_guid(guid)
             if str(self) in settings:
-                others, entries = fetch_crontab(self.username)
                 for attribute, entry in settings[str(self)].items():
-                    if entry in entries:
-                        entries.remove(entry)
-                    self.gp_db.delete(str(self), attribute)
-                with NamedTemporaryFile() as f:
-                    if len(entries) > 0:
-                        f.write('\n'.join([others, intro,
-                                '\n'.join(entries), end]).encode())
-                    else:
-                        f.write(others.encode())
-                    f.flush()
-                    install_crontab(f.name, self.username)
-            self.gp_db.commit()
+                    self.unapply(guid, attribute, entry)
 
         for gpo in changed_gpo_list:
             if gpo.file_sys_path:
                 section = \
                     'Software\\Policies\\Centrify\\UnixSettings\\CrontabEntries'
-                self.gp_db.set_guid(gpo.name)
                 pol_file = 'USER/Registry.pol'
                 path = os.path.join(gpo.file_sys_path, pol_file)
                 pol_conf = drop_privileges('root', self.parse, path)
                 if not pol_conf:
                     continue
+                attrs = []
                 for e in pol_conf.entries:
                     if e.keyname == section and e.data.strip():
-                        attribute = blake2b(e.data.encode()).hexdigest()
-                        old_val = self.gp_db.retrieve(str(self), attribute)
-                        others, entries = fetch_crontab(self.username)
-                        if not old_val or e.data not in entries:
-                            entries.append(e.data)
-                            with NamedTemporaryFile() as f:
-                                f.write('\n'.join([others, intro,
-                                        '\n'.join(entries), end]).encode())
-                                f.flush()
-                                install_crontab(f.name, self.username)
-                            self.gp_db.store(str(self), attribute, e.data)
-                        self.gp_db.commit()
+                        attribute = self.generate_attribute(e.data)
+                        attrs.append(attribute)
+                        self.apply(gpo.name, attribute, e.data)
+                self.clean(gpo.name, keep=attrs)
 
     def rsop(self, gpo):
         return super().rsop(gpo, target='USER')
diff --git a/python/samba/gp/gp_firefox_ext.py b/python/samba/gp/gp_firefox_ext.py
index 06ae31d7afb..a623314d411 100644
--- a/python/samba/gp/gp_firefox_ext.py
+++ b/python/samba/gp/gp_firefox_ext.py
@@ -16,7 +16,7 @@
 
 import os
 import json
-from samba.gp.gpclass import gp_pol_ext
+from samba.gp.gpclass import gp_pol_ext, gp_misc_applier
 from samba.dcerpc import misc
 from samba.common import get_string
 from samba.gp.util.logging import log
@@ -29,8 +29,8 @@ def parse_entry_data(e):
         return e.data == 1
     return e.data
 
-def convert_pol_to_json(policies, section, entries):
-    result = policies['policies']
+def convert_pol_to_json(section, entries):
+    result = {}
     index_map = {}
     for e in entries:
         if not e.keyname.startswith(section):
@@ -81,79 +81,121 @@ def convert_pol_to_json(policies, section, entries):
                 current[e.valuename] = parse_entry_data(e)
         else:
             result[e.valuename] = parse_entry_data(e)
-    return {'policies': result}
+    return result
 
-class gp_firefox_ext(gp_pol_ext):
-    __firefox_installdir1 = '/usr/lib64/firefox/distribution'
-    __firefox_installdir2 = '/etc/firefox/policies'
-    __destfile1 = os.path.join(__firefox_installdir1, 'policies.json')
-    __destfile2 = os.path.join(__firefox_installdir2, 'policies.json')
+class gp_firefox_ext(gp_pol_ext, gp_misc_applier):
+    firefox_installdir = '/etc/firefox/policies'
+    destfile = os.path.join(firefox_installdir, 'policies.json')
 
     def __str__(self):
         return 'Mozilla/Firefox'
 
     def set_machine_policy(self, policies):
         try:
-            os.makedirs(self.__firefox_installdir1, exist_ok=True)
-            with open(self.__destfile1, 'w') as f:
+            os.makedirs(self.firefox_installdir, exist_ok=True)
+            with open(self.destfile, 'w') as f:
                 json.dump(policies, f)
-                log.debug('Wrote Firefox preferences', self.__destfile1)
+                log.debug('Wrote Firefox preferences', self.destfile)
         except PermissionError:
             log.debug('Failed to write Firefox preferences',
-                              self.__destfile1)
-
-        try:
-            os.makedirs(self.__firefox_installdir2, exist_ok=True)
-            with open(self.__destfile2, 'w') as f:
-                json.dump(policies, f)
-                log.debug('Wrote Firefox preferences', self.__destfile2)
-        except PermissionError:
-            log.debug('Failed to write Firefox preferences',
-                              self.__destfile2)
+                              self.destfile)
 
     def get_machine_policy(self):
-        if os.path.exists(self.__destfile2):
-            with open(self.__destfile2, 'r') as r:
-                policies = json.load(r)
-                log.debug('Read Firefox preferences', self.__destfile2)
-        elif os.path.exists(self.__destfile1):
-            with open(self.__destfile1, 'r') as r:
+        if os.path.exists(self.destfile):
+            with open(self.destfile, 'r') as r:
                 policies = json.load(r)
-                log.debug('Read Firefox preferences', self.__destfile1)
+                log.debug('Read Firefox preferences', self.destfile)
         else:
             policies = {'policies': {}}
         return policies
 
+    def parse_value(self, value):
+        data = super().parse_value(value)
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except json.decoder.JSONDecodeError:
+                pass
+        return data
+
+    def unapply_policy(self, guid, policy, applied_val, val):
+        def set_val(policies, policy, val):
+            if val is None:
+                del policies[policy]
+            else:
+                policies[policy] = val
+        current = self.get_machine_policy()
+        if policy in current['policies'].keys():
+            if applied_val is not None:
+                # Only restore policy if unmodified
+                if current['policies'][policy] == applied_val:
+                    set_val(current['policies'], policy, val)
+            else:
+                set_val(current['policies'], policy, val)
+            self.set_machine_policy(current)
+
+    def unapply(self, guid, policy, val):
+        cache = self.parse_value(val)
+        if policy == 'policies.json':
+            current = self.get_machine_policy()
+            for attr in current['policies'].keys():
+                val = cache['old_val']['policies'][attr] \
+                        if attr in cache['old_val']['policies'] else None
+                self.unapply_policy(guid, attr, None, val)
+        else:
+            self.unapply_policy(guid, policy,
+                                cache['new_val'] if 'new_val' in cache else None,
+                                cache['old_val'])
+        self.cache_remove_attribute(guid, policy)
+
+    def apply(self, guid, policy, val):
+        # If the policy has changed, unapply, then apply new policy
+        data = self.cache_get_attribute_value(guid, policy)
+        if data is not None:
+            self.unapply(guid, policy, data)
+
+        current = self.get_machine_policy()
+        before = None
+        if policy in current['policies'].keys():
+            before = current['policies'][policy]
+
+        # Apply the policy and log the changes
+        new_value = self.generate_value(old_val=json.dumps(before),
+                                        new_val=json.dumps(val))
+        current['policies'][policy] = val
+        self.set_machine_policy(current)
+        self.cache_add_attribute(guid, policy, get_string(new_value))
+
     def process_group_policy(self, deleted_gpo_list, changed_gpo_list,
                              policy_dir=None):
         if policy_dir is not None:
-            self.__firefox_installdir2 = policy_dir
-            self.__destfile2 = os.path.join(policy_dir, 'policies.json')
+            self.firefox_installdir = policy_dir
+            self.destfile = os.path.join(policy_dir, 'policies.json')
         for guid, settings in deleted_gpo_list:
-            self.gp_db.set_guid(guid)
             if str(self) in settings:
-                for attribute, policies in settings[str(self)].items():
-                    self.set_machine_policy(json.loads(policies))
-                    self.gp_db.delete(str(self), attribute)
-            self.gp_db.commit()
+                for policy, val in settings[str(self)].items():
+                    self.unapply(guid, policy, val)
 
         for gpo in changed_gpo_list:
             if gpo.file_sys_path:
-                section = 'Software\\Policies\\Mozilla\\Firefox'
-                self.gp_db.set_guid(gpo.name)
                 pol_file = 'MACHINE/Registry.pol'
+                section = 'Software\\Policies\\Mozilla\\Firefox'
                 path = os.path.join(gpo.file_sys_path, pol_file)
                 pol_conf = self.parse(path)
                 if not pol_conf:
                     continue
 
-                policies = self.get_machine_policy()
-                self.gp_db.store(str(self), 'policies.json',
-                                 json.dumps(policies))
-                policies = convert_pol_to_json(policies, section,
-                                               pol_conf.entries)
-                self.set_machine_policy(policies)
-                self.gp_db.commit()
+                # Unapply the old cache entry, if present
+                data = self.cache_get_attribute_value(gpo.name, 'policies.json')
+                if data is not None:
+                    self.unapply(gpo.name, 'policies.json', data)
+
+                policies = convert_pol_to_json(section, pol_conf.entries)
+                for policy, val in policies.items():
+                    self.apply(gpo.name, policy, val)
+
+                # cleanup removed policies
+                self.clean(gpo.name, keep=policies.keys())
 
     def rsop(self, gpo):
         output = {}
@@ -168,3 +210,10 @@ class gp_firefox_ext(gp_pol_ext):
                 if e.keyname.startswith(section):
                     output['%s\\%s' % (e.keyname, e.valuename)] = e.data
         return output
+
+class gp_firefox_old_ext(gp_firefox_ext):
+    firefox_installdir = '/usr/lib64/firefox/distribution'
+    destfile = os.path.join(firefox_installdir, 'policies.json')
+
+    def __str__(self):
+        return 'Mozilla/Firefox (old profile directory)'
diff --git a/python/samba/gp/gp_firewalld_ext.py b/python/samba/gp/gp_firewalld_ext.py
index dd80d94c9cf..5e125b0fe46 100644
--- a/python/samba/gp/gp_firewalld_ext.py
+++ b/python/samba/gp/gp_firewalld_ext.py
@@ -16,10 +16,9 @@
 
 import os
 from subprocess import Popen, PIPE
-from hashlib import blake2b
 from shutil import which
 import json
-from samba.gp.gpclass import gp_pol_ext
+from samba.gp.gpclass import gp_pol_ext, gp_applier
 from samba.gp.util.logging import log
 
 def firewall_cmd(*args):
@@ -41,16 +40,19 @@ def rule_segment_parse(name, rule_segment):
         return '%s %s ' % (name,
             ' '.join(['%s=%s' % (k, v) for k, v in rule_segment.items()]))
 
-class gp_firewalld_ext(gp_pol_ext):
+class gp_firewalld_ext(gp_pol_ext, gp_applier):
     def __str__(self):
         return 'Security/Firewalld'
 
-    def apply_zone(self, zone):
+    def apply_zone(self, guid, zone):
+        zone_attrs = []
         ret = firewall_cmd('--permanent', '--new-zone=%s' % zone)[0]
         if ret != 0:
             log.error('Failed to add new zone', zone)
         else:
-            self.gp_db.store(str(self), 'zone:%s' % zone, zone)
+            attribute = 'zone:%s' % zone
+            self.cache_add_attribute(guid, attribute, zone)
+            zone_attrs.append(attribute)
         # Default to matching the interface(s) for the default zone
         ret, out = firewall_cmd('--list-interfaces')
         if ret != 0:
@@ -60,8 +62,10 @@ class gp_firewalld_ext(gp_pol_ext):
                                '--add-interface=%s' % interface.decode())
             if ret != 0:
                 log.error('Failed to set interfaces for zone', zone)
+        return zone_attrs
 
-    def apply_rules(self, rule_dict):
+    def apply_rules(self, guid, rule_dict):
+        rule_attrs = []
         for zone, rules in rule_dict.items():
             for rule in rules:
                 if 'rule' in rule:
@@ -88,50 +92,60 @@ class gp_firewalld_ext(gp_pol_ext):
                 if ret != 0:
                     log.error('Failed to add firewall rule', rule_parsed)
                 else:
-                    rhash = blake2b(rule_parsed.encode()).hexdigest()
-                    self.gp_db.store(str(self), 'rule:%s:%s' % (zone, rhash),
-                                     rule_parsed)
+                    rhash = self.generate_value_hash(rule_parsed)
+                    attribute = 'rule:%s:%s' % (zone, rhash)
+                    self.cache_add_attribute(guid, attribute, rule_parsed)
+                    rule_attrs.append(attribute)
+        return rule_attrs
+
+    def unapply(self, guid, attribute, value):
+        if attribute.startswith('zone'):
+            ret = firewall_cmd('--permanent',
+                               '--delete-zone=%s' % value)[0]
+            if ret != 0:
+                log.error('Failed to remove zone', value)
+            else:
+                self.cache_remove_attribute(guid, attribute)
+        elif attribute.startswith('rule'):
+            _, zone, _ = attribute.split(':')
+            ret = firewall_cmd('--permanent', '--zone=%s' % zone,
+                               '--remove-rich-rule', value)[0]
+            if ret != 0:
+                log.error('Failed to remove firewall rule', value)
+            else:
+                self.cache_remove_attribute(guid, attribute)
+
+    def apply(self, applier_func, *args):
+        return applier_func(*args)
 
     def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
         for guid, settings in deleted_gpo_list:
-            self.gp_db.set_guid(guid)
             if str(self) in settings:
                 for attribute, value in settings[str(self)].items():
-                    if attribute.startswith('zone'):
-                        ret = firewall_cmd('--permanent',
-                                           '--delete-zone=%s' % value)[0]
-                        if ret != 0:
-                            log.error('Failed to remove zone', value)
-                        else:
-                            self.gp_db.delete(str(self), attribute)
-                    elif attribute.startswith('rule'):
-                        _, zone, _ = attribute.split(':')
-                        ret = firewall_cmd('--permanent', '--zone=%s' % zone,
-                                           '--remove-rich-rule', value)[0]
-                        if ret != 0:
-                            log.error('Failed to remove firewall rule', value)
-                        else:
-                            self.gp_db.delete(str(self), attribute)
-            self.gp_db.commit()
+                    self.unapply(guid, attribute, value)
 
         for gpo in changed_gpo_list:
             if gpo.file_sys_path:
                 section = 'Software\\Policies\\Samba\\Unix Settings\\Firewalld'
-                self.gp_db.set_guid(gpo.name)
                 pol_file = 'MACHINE/Registry.pol'
                 path = os.path.join(gpo.file_sys_path, pol_file)
                 pol_conf = self.parse(path)
                 if not pol_conf:
                     continue
+                attrs = []
                 for e in pol_conf.entries:
                     if e.keyname.startswith(section):
                         if e.keyname.endswith('Rules'):
-                            self.apply_rules(json.loads(e.data))
+                            attrs.extend(self.apply(self.apply_rules, gpo.name,
+                                                    json.loads(e.data)))
                         elif e.keyname.endswith('Zones'):
                             if e.valuename == '**delvals.':
                                 continue
-                            self.apply_zone(e.data)
-                self.gp_db.commit()
+                            attrs.extend(self.apply(self.apply_zone, gpo.name,
+                                                    e.data))
+
+                # Cleanup all old zones and rules from this GPO
+                self.clean(gpo.name, keep=attrs)
 
     def rsop(self, gpo):
         output = {}
diff --git a/python/samba/gp/gp_msgs_ext.py b/python/samba/gp/gp_msgs_ext.py
index 267c7456ad1..f1a13323c4d 100644
--- a/python/samba/gp/gp_msgs_ext.py
+++ b/python/samba/gp/gp_msgs_ext.py
@@ -15,57 +15,65 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
-from samba.gp.gpclass import gp_pol_ext
+from samba.gp.gpclass import gp_pol_ext, gp_misc_applier
+
+class gp_msgs_ext(gp_pol_ext, gp_misc_applier):
+    def unapply(self, guid, cdir, attribute, value):
+        if attribute not in ['motd', 'issue']:
+            raise ValueError('"%s" is not a message attribute' % attribute)
+        data = self.parse_value(value)
+        mfile = os.path.join(cdir, attribute)
+        current = open(mfile, 'r').read() if os.path.exists(mfile) else ''
+        # Only overwrite the msg if it hasn't been modified. It may have been
+        # modified by another GPO.
+        if 'new_val' not in data or current.strip() == data['new_val'].strip():
+            msg = data['old_val']
+            with open(mfile, 'w') as w:
+                if msg:
+                    w.write(msg)
+                else:
+                    w.truncate()
+        self.cache_remove_attribute(guid, attribute)
+
+    def apply(self, guid, cdir, entries):
+        section_name = 'Software\\Policies\\Samba\\Unix Settings\\Messages'
+        for e in entries:
+            if e.keyname == section_name and e.data.strip():
+                if e.valuename not in ['motd', 'issue']:
+                    raise ValueError('"%s" is not a message attribute' % \
+                            e.valuename)
+                mfile = os.path.join(cdir, e.valuename)
+                if os.path.exists(mfile):
+                    old_val = open(mfile, 'r').read()
+                else:
+                    old_val = ''
+                # If policy is already applied, skip application
+                if old_val.strip() == e.data.strip():
+                    return
+                with open(mfile, 'w') as w:
+                    w.write(e.data)
+                data = self.generate_value(old_val=old_val, new_val=e.data)
+                self.cache_add_attribute(guid, e.valuename, data)
 
-class gp_msgs_ext(gp_pol_ext):
     def __str__(self):
         return 'Unix Settings/Messages'
 


-- 
Samba Shared Repository



More information about the samba-cvs mailing list