gpo: Extract Access policy from Security extension
authorDavid Mulder <dmulder@suse.com>
Wed, 8 Jul 2020 20:48:45 +0000 (14:48 -0600)
committerDavid Mulder <dmulder@samba.org>
Thu, 6 Aug 2020 16:38:36 +0000 (16:38 +0000)
Rewrite the extension to be easier to understand,
and to remove references to gp_ext_setter.

Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
python/samba/gp_sec_ext.py
python/samba/tests/gpo.py
source4/scripting/bin/samba-gpupdate

index fde1f22269296fbfd5c946c506cd7a751cf5ba79..cdc45360a00c4e15c99b7eb63ba4f7312456245c 100644 (file)
@@ -103,14 +103,14 @@ class gp_krb_ext(gp_inf_ext):
         return output
 
 
-class inf_to_ldb(gp_ext_setter):
+class gp_access_ext(gp_inf_ext):
     '''This class takes the .inf file parameter (essentially a GPO file mapped
     to a GUID), hashmaps it to the Samba parameter, which then uses an ldb
     object to update the parameter to Samba4. Not registry oriented whatsoever.
     '''
 
-    def __init__(self, logger, gp_db, lp, creds, key, value):
-        super(inf_to_ldb, self).__init__(logger, gp_db, lp, creds, key, value)
+    def __init__(self, *args):
+        super().__init__(*args)
         try:
             self.ldb = SamDB(self.lp.samdb_url(),
                              session_info=system_session(),
@@ -119,41 +119,73 @@ class inf_to_ldb(gp_ext_setter):
         except (NameError, LdbError):
             raise Exception('Failed to load SamDB for assigning Group Policy')
 
-    def ch_minPwdAge(self, val):
+    apply_map = { 'MinimumPasswordAge':     'minPwdAge',
+                  'MaximumPasswordAge':     'maxPwdAge',
+                  'MinimumPasswordLength':  'minPwdLength',
+                  'PasswordComplexity':     'pwdProperties' }
+    def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
+        if self.lp.get('server role') != 'active directory domain controller':
+            return
+        inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
+        for gpo in deleted_gpo_list:
+            self.gp_db.set_guid(gpo[0])
+            for section in gpo[1].keys():
+                if section == str(self):
+                    for att, value in gpo[1][section].items():
+                        update_samba, _ = self.mapper().get(att)
+                        update_samba(att, value)
+                        self.gp_db.delete(section, att)
+                        self.gp_db.commit()
+
+        for gpo in changed_gpo_list:
+            if gpo.file_sys_path:
+                self.gp_db.set_guid(gpo.name)
+                path = os.path.join(gpo.file_sys_path, inf_file)
+                inf_conf = self.parse(path)
+                if not inf_conf:
+                    continue
+                for section in inf_conf.sections():
+                    if section == str(self):
+                        for key, value in inf_conf.items(section):
+                            att = gp_access_ext.apply_map[key]
+                            (update_samba, value_func) = self.mapper().get(att)
+                            update_samba(att, value_func(value))
+                            self.gp_db.commit()
+
+    def ch_minPwdAge(self, attribute, val):
         old_val = self.ldb.get_minPwdAge()
         self.logger.info('KDC Minimum Password age was changed from %s to %s'
                          % (old_val, val))
-        self.gp_db.store(str(self), self.attribute, str(old_val))
+        self.gp_db.store(str(self), attribute, str(old_val))
         self.ldb.set_minPwdAge(val)
 
-    def ch_maxPwdAge(self, val):
+    def ch_maxPwdAge(self, attribute, val):
         old_val = self.ldb.get_maxPwdAge()
         self.logger.info('KDC Maximum Password age was changed from %s to %s'
                          % (old_val, val))
-        self.gp_db.store(str(self), self.attribute, str(old_val))
+        self.gp_db.store(str(self), attribute, str(old_val))
         self.ldb.set_maxPwdAge(val)
 
-    def ch_minPwdLength(self, val):
+    def ch_minPwdLength(self, attribute, val):
         old_val = self.ldb.get_minPwdLength()
         self.logger.info(
             'KDC Minimum Password length was changed from %s to %s'
             % (old_val, val))
-        self.gp_db.store(str(self), self.attribute, str(old_val))
+        self.gp_db.store(str(self), attribute, str(old_val))
         self.ldb.set_minPwdLength(val)
 
-    def ch_pwdProperties(self, val):
+    def ch_pwdProperties(self, attribute, val):
         old_val = self.ldb.get_pwdProperties()
         self.logger.info('KDC Password Properties were changed from %s to %s'
                          % (old_val, val))
-        self.gp_db.store(str(self), self.attribute, str(old_val))
+        self.gp_db.store(str(self), attribute, str(old_val))
         self.ldb.set_pwdProperties(val)
 
-    def days2rel_nttime(self):
+    def days2rel_nttime(self, val):
         seconds = 60
         minutes = 60
         hours = 24
         sam_add = 10000000
-        val = (self.val)
         val = int(val)
         return str(-(val * seconds * minutes * hours * sam_add))
 
@@ -163,94 +195,23 @@ class inf_to_ldb(gp_ext_setter):
                 "maxPwdAge": (self.ch_maxPwdAge, self.days2rel_nttime),
                 # Could be none, but I like the method assignment in
                 # update_samba
-                "minPwdLength": (self.ch_minPwdLength, self.explicit),
-                "pwdProperties": (self.ch_pwdProperties, self.explicit),
+                "minPwdLength": (self.ch_minPwdLength, lambda val: val),
+                "pwdProperties": (self.ch_pwdProperties, lambda val: val),
 
                 }
 
     def __str__(self):
         return 'System Access'
 
-
-class gp_sec_ext(gp_inf_ext):
-    '''This class does the following two things:
-        1) Identifies the GPO if it has a certain kind of filepath,
-        2) Finally parses it.
-    '''
-
-    count = 0
-
-    def __str__(self):
-        return "Security GPO extension"
-
-    def apply_map(self):
-        return {"System Access": {"MinimumPasswordAge": ("minPwdAge",
-                                                         inf_to_ldb),
-                                  "MaximumPasswordAge": ("maxPwdAge",
-                                                         inf_to_ldb),
-                                  "MinimumPasswordLength": ("minPwdLength",
-                                                            inf_to_ldb),
-                                  "PasswordComplexity": ("pwdProperties",
-                                                         inf_to_ldb),
-                                  },
-                }
-
-    def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
-        if self.lp.get('server role') != 'active directory domain controller':
-            return
-        inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
-        apply_map = self.apply_map()
-        for gpo in deleted_gpo_list:
-            self.gp_db.set_guid(gpo[0])
-            for section in gpo[1].keys():
-                current_section = apply_map.get(section)
-                if not current_section:
-                    continue
-                for key, value in gpo[1][section].items():
-                    setter = None
-                    for _, tup in current_section.items():
-                        if tup[0] == key:
-                            setter = tup[1]
-                    if setter:
-                        value = value.encode('ascii', 'ignore') \
-                             if value else value
-                        setter(self.logger, self.gp_db, self.lp, self.creds,
-                               key, value).delete()
-                        self.gp_db.delete(section, key)
-                        self.gp_db.commit()
-
-        for gpo in changed_gpo_list:
-            if gpo.file_sys_path:
-                self.gp_db.set_guid(gpo.name)
-                path = os.path.join(gpo.file_sys_path, inf_file)
-                inf_conf = self.parse(path)
-                if not inf_conf:
-                    continue
-                for section in inf_conf.sections():
-                    current_section = apply_map.get(section)
-                    if not current_section:
-                        continue
-                    for key, value in inf_conf.items(section):
-                        if current_section.get(key):
-                            (att, setter) = current_section.get(key)
-                            value = value.encode('ascii', 'ignore')
-                            setter(self.logger, self.gp_db, self.lp,
-                                   self.creds, att, value).update_samba()
-                            self.gp_db.commit()
-
     def rsop(self, gpo):
         output = {}
         inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
-        apply_map = self.apply_map()
         if gpo.file_sys_path:
             path = os.path.join(gpo.file_sys_path, inf_file)
             inf_conf = self.parse(path)
             if not inf_conf:
                 return output
             for section in inf_conf.sections():
-                current_section = apply_map.get(section)
-                if not current_section:
-                    continue
                 output[section] = {k: v for k, v in inf_conf.items(section) \
-                                      if current_section.get(k)}
+                                      if gp_access_ext.apply_map.get(k)}
         return output
index f2927373dc004862f8e2939a73d5d861664245fa..6b9106cb45012aba16edf0986985ca325522f90d 100644 (file)
@@ -24,7 +24,7 @@ from samba.gpclass import check_refresh_gpo_list, check_safe_path, \
     check_guid, parse_gpext_conf, atomic_write_conf, get_deleted_gpos_list
 from subprocess import Popen, PIPE
 from tempfile import NamedTemporaryFile, TemporaryDirectory
-from samba.gp_sec_ext import gp_krb_ext, gp_sec_ext
+from samba.gp_sec_ext import gp_krb_ext, gp_access_ext
 from samba.gp_scripts_ext import gp_scripts_ext
 from samba.gp_sudoers_ext import gp_sudoers_ext
 from samba.gpclass import gp_inf_ext
@@ -176,7 +176,7 @@ class GPOTests(tests.TestCase):
         samba_path = os.path.realpath(os.path.join(this_path, '../../../'))
         ext_path = os.path.join(samba_path, 'python/samba/gp_sec_ext.py')
         ext_guid = '{827D319E-6EAC-11D2-A4EA-00C04F79F83A}'
-        ret = register_gp_extension(ext_guid, 'gp_sec_ext', ext_path,
+        ret = register_gp_extension(ext_guid, 'gp_access_ext', ext_path,
                                     smb_conf=self.lp.configfile,
                                     machine=True, user=False)
         self.assertTrue(ret, 'Failed to register a gp ext')
index 39c5d2cf5cd34b83e0143994dc4532a9ae8a66e5..33e1fb793fc8a5047f533b246f39b669b22b79ea 100755 (executable)
@@ -30,7 +30,7 @@ sys.path.insert(0, "bin/python")
 import optparse
 from samba import getopt as options
 from samba.gpclass import apply_gp, unapply_gp, GPOStorage, rsop
-from samba.gp_sec_ext import gp_krb_ext, gp_sec_ext
+from samba.gp_sec_ext import gp_krb_ext, gp_access_ext
 from samba.gp_ext_loader import get_gp_client_side_extensions
 from samba.gp_scripts_ext import gp_scripts_ext
 from samba.gp_sudoers_ext import gp_sudoers_ext
@@ -83,7 +83,7 @@ if __name__ == "__main__":
                                                             lp.configfile)
     gp_extensions = []
     if opts.target == 'Computer':
-        gp_extensions.append(gp_sec_ext(logger, lp, creds, store))
+        gp_extensions.append(gp_access_ext(logger, lp, creds, store))
         gp_extensions.append(gp_krb_ext(logger, lp, creds, store))
         gp_extensions.append(gp_scripts_ext(logger, lp, creds, store))
         gp_extensions.append(gp_sudoers_ext(logger, lp, creds, store))