gpo: Dynamically load gp_exts
authorDavid Mulder <dmulder@suse.com>
Wed, 9 May 2018 15:24:37 +0000 (09:24 -0600)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 12 Jul 2018 20:11:23 +0000 (22:11 +0200)
This loads Group Policy Client Side Extensions
similar to the way that they are loaded on a
Windows client. Extensions are installed to a
configuration file in the samba cache path where
they receive a unique GUID matched with the path
to the python gp_ext file. Classes which inherit
from the gp_ext class (as defined in gpclass.py)
will be dynamically loaded.

Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/gp_ext_loader.py [new file with mode: 0644]
source4/scripting/bin/samba-gpupdate

diff --git a/python/samba/gp_ext_loader.py b/python/samba/gp_ext_loader.py
new file mode 100644 (file)
index 0000000..d25b283
--- /dev/null
@@ -0,0 +1,51 @@
+# Group Policy Client Side Extension Loader
+# Copyright (C) David Mulder <dmulder@suse.com> 2018
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty 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, see <http://www.gnu.org/licenses/>.
+
+import os
+from samba.gpclass import list_gp_extensions
+from samba.gpclass import gp_ext
+
+try:
+    import importlib.util
+    def import_file(name, location):
+        spec = importlib.util.spec_from_file_location(name, location)
+        module = importlib.util.module_from_spec(spec)
+        spec.loader.exec_module(module)
+        return module
+except ImportError:
+    import imp
+    def import_file(name, location):
+        return imp.load_source(name, location)
+
+def get_gp_ext_from_module(name, mod):
+    if mod:
+        for k, v in vars(mod).items():
+            if k == name and issubclass(v, gp_ext):
+                return v
+    return None
+
+def get_gp_client_side_extensions(logger, smb_conf):
+    machine_exts = []
+    gp_exts = list_gp_extensions(smb_conf)
+    for gp_ext in gp_exts.values():
+        module = import_file(gp_ext['ProcessGroupPolicy'], gp_ext['DllName'])
+        ext = get_gp_ext_from_module(gp_ext['ProcessGroupPolicy'], module)
+        if ext and gp_ext['MachinePolicy']:
+            machine_exts.append(ext)
+            logger.info('Loaded machine extension from %s: %s'
+                        % (gp_ext['DllName'], ext.__name__))
+    return machine_exts
+
index 647acd9ada15368e7a6b551546baaa9a22ed47a7..e3d31ebbfb64d3ac2ea57f5354615f288f1e7868 100755 (executable)
@@ -36,6 +36,7 @@ except:
     SamDB = None
 from samba.gpclass import apply_gp, unapply_gp, GPOStorage
 from samba.gp_sec_ext import gp_sec_ext
+from samba.gp_ext_loader import get_gp_client_side_extensions
 import logging
 
 if __name__ == "__main__":
@@ -84,10 +85,13 @@ if __name__ == "__main__":
     cache_dir = lp.get('cache directory')
     store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
 
+    machine_exts = get_gp_client_side_extensions(logger, lp.configfile)
     gp_extensions = []
     if opts.target == 'Computer':
         if lp.get('server role') == 'active directory domain controller':
             gp_extensions.append(gp_sec_ext(logger))
+        for ext in machine_exts:
+            gp_extensions.append(ext(logger))
     elif opts.target == 'User':
         pass # User extensions