[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Thu Jul 12 23:06:11 UTC 2018


The branch, master has been updated
       via  f3358f0 gpo: Specify samba module when importing from gpclass
       via  b05b619 gpo: Don't duplicate guids in the apply log
       via  de8b30a gpo: Add user policy extensions
       via  126b789 gpo: Dynamically load gp_exts
       via  fb6c250 gpo: Tests for gp_ext register/unregister
       via  4436b67 gpo: add list_gp_extensions for listing registered gp extensions
       via  b4f09af gpo: add unregister_gp_extension for unregistering gp extensions
       via  387dc35 gpo: add register_gp_extension for registering gp extensions
       via  46629f5 param: Add python binding for lpcfg_state_path
       via  2412c70 gpo: Offline policy application via cache
       via  57faf35 gpo: Read GPO versions locally, not from sysvol
       via  4c7348e python: Allow forced signing via smb.SMB()
       via  2494e33 gpo: Disable python3 testing
       via  ce9ac51 gpo: Fix asserts in gpo testing
      from  3eee52b pthreadpool: allocate glue->tctx on glue as memory context.

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


- Log -----------------------------------------------------------------
commit f3358f048d7583bb63cb0f09efdd68fbbe49d32e
Author: David Mulder <dmulder at suse.com>
Date:   Wed May 16 09:03:32 2018 -0600

    gpo: Specify samba module when importing from gpclass
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    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): Fri Jul 13 01:05:22 CEST 2018 on sn-devel-144

commit b05b6198a3fa480e7026145bfd0608e41fd3f326
Author: David Mulder <dmulder at suse.com>
Date:   Tue May 15 08:37:08 2018 -0600

    gpo: Don't duplicate guids in the apply log
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit de8b30a726bcef3f8c5e37b1f27c97020f4fb051
Author: David Mulder <dmulder at suse.com>
Date:   Fri May 4 13:25:25 2018 -0600

    gpo: Add user policy extensions
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 126b789268a3a21ee4d5769290b69d45860bb608
Author: David Mulder <dmulder at suse.com>
Date:   Wed May 9 09:24:37 2018 -0600

    gpo: Dynamically load gp_exts
    
    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 at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit fb6c250bdeebfd00d1605dd76ac54d1013ea4ba2
Author: David Mulder <dmulder at suse.com>
Date:   Wed Jul 11 17:09:26 2018 +1200

    gpo: Tests for gp_ext register/unregister
    
    Adds testing for the gp_ext register and
    unregister functions, as well as testing
    the list function.
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 4436b6703c081d0479af407d4c8ea28f5a323f88
Author: David Mulder <dmulder at suse.com>
Date:   Wed Jun 13 14:46:30 2018 -0600

    gpo: add list_gp_extensions for listing registered gp extensions
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b4f09af27abc8da260a1c1b2ea074f9f6e5ce56b
Author: David Mulder <dmulder at suse.com>
Date:   Wed Jun 13 14:46:05 2018 -0600

    gpo: add unregister_gp_extension for unregistering gp extensions
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 387dc358d3a2bd33bca7d7bcbcb2668eae6c0bd5
Author: David Mulder <dmulder at suse.com>
Date:   Wed Jun 13 14:45:09 2018 -0600

    gpo: add register_gp_extension for registering gp extensions
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 46629f53217f269c3bea044b054e62381149443c
Author: David Mulder <dmulder at suse.com>
Date:   Fri Jun 29 14:08:34 2018 -0600

    param: Add python binding for lpcfg_state_path
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 2412c70481fe22fb9e266e6ef1a1cd86fb39a1e5
Author: David Mulder <dmulder at suse.com>
Date:   Wed May 16 10:37:09 2018 -0600

    gpo: Offline policy application via cache
    
    Read policy files from the cache, rather than
    the sysvol. This enables offline policy apply.
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 57faf35cf836e675e088b3a6e6e455c1309fd4ea
Author: David Mulder <dmulder at suse.com>
Date:   Mon Jan 8 07:17:29 2018 -0700

    gpo: Read GPO versions locally, not from sysvol
    
    Non-kdc clients cannot read directly from the
    sysvol, so we need to store the GPT.INI file
    locally to read each gpo version.
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 4c7348e44d10ca519dd1322fd40b12c69e17a8e6
Author: David Mulder <dmulder at suse.com>
Date:   Thu Jun 28 09:01:59 2018 -0600

    python: Allow forced signing via smb.SMB()
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 2494e33822276cc6a8836121b3012f9e94b9fddf
Author: David Mulder <dmulder at suse.com>
Date:   Wed Jun 13 14:42:43 2018 -0600

    gpo: Disable python3 testing
    
    The gpo module doesn't work in python3 yet,
    causing this test to fail on python3.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13525
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit ce9ac51ee223271a789fa7aee215acd383fa33a3
Author: David Mulder <dmulder at suse.com>
Date:   Thu Jul 5 09:02:57 2018 -0600

    gpo: Fix asserts in gpo testing
    
    These tests weren't using python's unit testing
    asserts.
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

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

Summary of changes:
 python/samba/gp_ext_loader.py        |  56 ++++++++++++
 python/samba/gp_sec_ext.py           |   2 +-
 python/samba/gpclass.py              | 170 ++++++++++++++++++++++++++++-------
 python/samba/tests/gpo.py            |  98 +++++++++++++++++---
 source4/libcli/pysmb.c               |  10 ++-
 source4/param/pyparam.c              |  27 ++++++
 source4/scripting/bin/samba-gpupdate |   8 +-
 source4/selftest/tests.py            |   2 +-
 8 files changed, 322 insertions(+), 51 deletions(-)
 create mode 100644 python/samba/gp_ext_loader.py


Changeset truncated at 500 lines:

diff --git a/python/samba/gp_ext_loader.py b/python/samba/gp_ext_loader.py
new file mode 100644
index 0000000..61cc29b
--- /dev/null
+++ b/python/samba/gp_ext_loader.py
@@ -0,0 +1,56 @@
+# Group Policy Client Side Extension Loader
+# Copyright (C) David Mulder <dmulder at 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):
+    user_exts = []
+    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__))
+        if ext and gp_ext['UserPolicy']:
+            user_exts.append(ext)
+            logger.info('Loaded user extension from %s: %s'
+                        % (gp_ext['DllName'], ext.__name__))
+    return (machine_exts, user_exts)
+
diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py
index bbd385f..11fd1f5 100644
--- a/python/samba/gp_sec_ext.py
+++ b/python/samba/gp_sec_ext.py
@@ -16,7 +16,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os.path
-from gpclass import gp_ext_setter, gp_inf_ext
+from samba.gpclass import gp_ext_setter, gp_inf_ext
 
 class inf_to_kdc_tdb(gp_ext_setter):
     def mins_to_hours(self):
diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index 0966611..70ab261 100644
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -17,6 +17,7 @@
 
 import sys
 import os
+import errno
 import tdb
 sys.path.insert(0, "bin/python")
 from samba import NTSTATUSError
@@ -29,6 +30,9 @@ from samba.net import Net
 from samba.dcerpc import nbt
 from samba import smb
 import samba.gpo as gpo
+from samba.param import LoadParm
+from uuid import UUID
+from tempfile import NamedTemporaryFile
 
 try:
     from enum import Enum
@@ -135,9 +139,11 @@ class gp_log:
             apply_log = user_obj.find('applylog')
             if apply_log is None:
                 apply_log = etree.SubElement(user_obj, 'applylog')
-            item = etree.SubElement(apply_log, 'guid')
-            item.attrib['count'] = '%d' % (len(apply_log)-1)
-            item.attrib['value'] = guid
+            prev = apply_log.find('guid[@value="%s"]' % guid)
+            if prev is None:
+                item = etree.SubElement(apply_log, 'guid')
+                item.attrib['count'] = '%d' % (len(apply_log)-1)
+                item.attrib['value'] = guid
 
     def apply_log_pop(self):
         ''' Pop a GPO guid from the applylog
@@ -305,32 +311,16 @@ class gp_ext(object):
     def read(self, policy):
         pass
 
-    def parse(self, afile, ldb, conn, gp_db, lp):
+    def parse(self, afile, ldb, gp_db, lp):
         self.ldb = ldb
         self.gp_db = gp_db
         self.lp = lp
 
-        # Fixing the bug where only some Linux Boxes capitalize MACHINE
-        try:
-            blist = afile.split('/')
-            idx = afile.lower().split('/').index('machine')
-            for case in [
-                            blist[idx].upper(),
-                            blist[idx].capitalize(),
-                            blist[idx].lower()
-                        ]:
-                bfile = '/'.join(blist[:idx]) + '/' + case + '/' + \
-                    '/'.join(blist[idx+1:])
-                try:
-                    return self.read(conn.loadfile(bfile.replace('/', '\\')))
-                except NTSTATUSError:
-                    continue
-        except ValueError:
-            try:
-                return self.read(conn.loadfile(afile.replace('/', '\\')))
-            except Exception as e:
-                self.logger.error(str(e))
-                return None
+        local_path = self.lp.cache_path('gpo_cache')
+        data_file = os.path.join(local_path, check_safe_path(afile).upper())
+        if os.path.exists(data_file):
+            return self.read(open(data_file, 'r').read())
+        return None
 
     @abstractmethod
     def __str__(self):
@@ -423,23 +413,66 @@ def get_gpo_list(dc_hostname, creds, lp):
         gpos = ads.get_gpo_list(creds.get_username())
     return gpos
 
+
+def cache_gpo_dir(conn, cache, sub_dir):
+    loc_sub_dir = sub_dir.upper()
+    local_dir = os.path.join(cache, loc_sub_dir)
+    try:
+        os.makedirs(local_dir, mode=0o755)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+    for fdata in conn.list(sub_dir):
+        if fdata['attrib'] & smb.FILE_ATTRIBUTE_DIRECTORY:
+            cache_gpo_dir(conn, cache, os.path.join(sub_dir, fdata['name']))
+        else:
+            local_name = fdata['name'].upper()
+            f = NamedTemporaryFile(delete=False, dir=local_dir)
+            fname = os.path.join(sub_dir, fdata['name']).replace('/', '\\')
+            f.write(conn.loadfile(fname))
+            f.close()
+            os.rename(f.name, os.path.join(local_dir, local_name))
+
+
+def check_safe_path(path):
+    dirs = re.split('/|\\\\', path)
+    if 'sysvol' in path:
+        dirs = dirs[dirs.index('sysvol')+1:]
+    if not '..' in dirs:
+        return os.path.join(*dirs)
+    raise OSError(path)
+
+def check_refresh_gpo_list(dc_hostname, lp, creds, gpos):
+    conn = smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds, sign=True)
+    cache_path = lp.cache_path('gpo_cache')
+    for gpo in gpos:
+        if not gpo.file_sys_path:
+            continue
+        cache_gpo_dir(conn, cache_path, check_safe_path(gpo.file_sys_path))
+
+def gpo_version(lp, path):
+    # gpo.gpo_get_sysvol_gpt_version() reads the GPT.INI from a local file,
+    # read from the gpo client cache.
+    gpt_path = lp.cache_path(os.path.join('gpo_cache', path))
+    return int(gpo.gpo_get_sysvol_gpt_version(gpt_path)[1])
+
 def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
     gp_db = store.get_gplog(creds.get_username())
     dc_hostname = get_dc_hostname(creds, lp)
+    gpos = get_gpo_list(dc_hostname, creds, lp)
     try:
-        conn =  smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
+        check_refresh_gpo_list(dc_hostname, lp, creds, gpos)
     except:
-        logger.error('Error connecting to \'%s\' using SMB' % dc_hostname)
-        raise
-    gpos = get_gpo_list(dc_hostname, creds, lp)
+        logger.error('Failed downloading gpt cache from \'%s\' using SMB' \
+            % dc_hostname)
+        return
 
     for gpo_obj in gpos:
         guid = gpo_obj.name
         if guid == 'Local Policy':
             continue
-        path = os.path.join(lp.get('realm').lower(), 'Policies', guid)
-        local_path = os.path.join(lp.get("path", "sysvol"), path)
-        version = int(gpo.gpo_get_sysvol_gpt_version(local_path)[1])
+        path = os.path.join(lp.get('realm'), 'Policies', guid).upper()
+        version = gpo_version(lp, path)
         if version != store.get_int(guid):
             logger.info('GPO %s has changed' % guid)
             gp_db.state(GPOSTATE.APPLY)
@@ -449,7 +482,7 @@ def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
         store.start()
         for ext in gp_extensions:
             try:
-                ext.parse(ext.list(path), test_ldb, conn, gp_db, lp)
+                ext.parse(ext.list(path), test_ldb, gp_db, lp)
             except Exception as e:
                 logger.error('Failed to parse gpo %s for extension %s' % \
                     (guid, str(ext)))
@@ -479,3 +512,74 @@ def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
             gp_db.delete(str(attr_obj), attr[0])
         gp_db.commit()
 
+def parse_gpext_conf(smb_conf):
+    lp = LoadParm()
+    if smb_conf is not None:
+        lp.load(smb_conf)
+    else:
+        lp.load_default()
+    ext_conf = lp.state_path('gpext.conf')
+    parser = ConfigParser()
+    parser.read(ext_conf)
+    return lp, parser
+
+def atomic_write_conf(lp, parser):
+    ext_conf = lp.state_path('gpext.conf')
+    with NamedTemporaryFile(delete=False, dir=os.path.dirname(ext_conf)) as f:
+        parser.write(f)
+        os.rename(f.name, ext_conf)
+
+def check_guid(guid):
+    # Check for valid guid with curly braces
+    if guid[0] != '{' or guid[-1] != '}' or len(guid) != 38:
+        return False
+    try:
+        UUID(guid, version=4)
+    except ValueError:
+        return False
+    return True
+
+def register_gp_extension(guid, name, path,
+                          smb_conf=None, machine=True, user=True):
+    # Check that the module exists
+    if not os.path.exists(path):
+        return False
+    if not check_guid(guid):
+        return False
+
+    lp, parser = parse_gpext_conf(smb_conf)
+    if not guid in parser.sections():
+        parser.add_section(guid)
+    parser.set(guid, 'DllName', path)
+    parser.set(guid, 'ProcessGroupPolicy', name)
+    parser.set(guid, 'NoMachinePolicy', 0 if machine else 1)
+    parser.set(guid, 'NoUserPolicy', 0 if user else 1)
+
+    atomic_write_conf(lp, parser)
+
+    return True
+
+def list_gp_extensions(smb_conf=None):
+    _, parser = parse_gpext_conf(smb_conf)
+    results = {}
+    for guid in parser.sections():
+        results[guid] = {}
+        results[guid]['DllName'] = parser.get(guid, 'DllName')
+        results[guid]['ProcessGroupPolicy'] = \
+            parser.get(guid, 'ProcessGroupPolicy')
+        results[guid]['MachinePolicy'] = \
+            not int(parser.get(guid, 'NoMachinePolicy'))
+        results[guid]['UserPolicy'] = not int(parser.get(guid, 'NoUserPolicy'))
+    return results
+
+def unregister_gp_extension(guid, smb_conf=None):
+    if not check_guid(guid):
+        return False
+
+    lp, parser = parse_gpext_conf(smb_conf)
+    if guid in parser.sections():
+        parser.remove_section(guid)
+
+    atomic_write_conf(lp, parser)
+
+    return True
diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py
index 796a5cb..27f52af 100644
--- a/python/samba/tests/gpo.py
+++ b/python/samba/tests/gpo.py
@@ -16,7 +16,11 @@
 
 import os
 from samba import gpo, tests
+from samba.gpclass import register_gp_extension, list_gp_extensions, \
+    unregister_gp_extension
 from samba.param import LoadParm
+from samba.gpclass import check_refresh_gpo_list, check_safe_path, \
+    check_guid, parse_gpext_conf, atomic_write_conf
 
 poldir = r'\\addom.samba.example.com\sysvol\addom.samba.example.com\Policies'
 dspath = 'CN=Policies,CN=System,DC=addom,DC=samba,DC=example,DC=com'
@@ -43,12 +47,12 @@ class GPOTests(tests.TestCase):
         file_sys_paths = [None, '%s\\%s' % (poldir, guid)]
         ds_paths = [None, 'CN=%s,%s' % (guid, dspath)]
         for i in range(0, len(gpos)):
-            assert gpos[i].name == names[i], \
-              'The gpo name did not match expected name %s' % gpos[i].name
-            assert gpos[i].file_sys_path == file_sys_paths[i], \
-              'file_sys_path did not match expected %s' % gpos[i].file_sys_path
-            assert gpos[i].ds_path == ds_paths[i], \
-              'ds_path did not match expected %s' % gpos[i].ds_path
+            self.assertEquals(gpos[i].name, names[i],
+              'The gpo name did not match expected name %s' % gpos[i].name)
+            self.assertEquals(gpos[i].file_sys_path, file_sys_paths[i],
+              'file_sys_path did not match expected %s' % gpos[i].file_sys_path)
+            self.assertEquals(gpos[i].ds_path, ds_paths[i],
+              'ds_path did not match expected %s' % gpos[i].ds_path)
 
 
     def test_gpo_ads_does_not_segfault(self):
@@ -59,19 +63,89 @@ class GPOTests(tests.TestCase):
 
     def test_gpt_version(self):
         global gpt_data
-        local_path = self.lp.get("path", "sysvol")
-        policies = 'addom.samba.example.com/Policies'
+        local_path = self.lp.cache_path('gpo_cache')
+        policies = 'ADDOM.SAMBA.EXAMPLE.COM/POLICIES'
         guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
         gpo_path = os.path.join(local_path, policies, guid)
         old_vers = gpo.gpo_get_sysvol_gpt_version(gpo_path)[1]
 
         with open(os.path.join(gpo_path, 'GPT.INI'), 'w') as gpt:
             gpt.write(gpt_data % 42)
-        assert gpo.gpo_get_sysvol_gpt_version(gpo_path)[1] == 42, \
-          'gpo_get_sysvol_gpt_version() did not return the expected version'
+        self.assertEquals(gpo.gpo_get_sysvol_gpt_version(gpo_path)[1], 42,
+          'gpo_get_sysvol_gpt_version() did not return the expected version')
 
         with open(os.path.join(gpo_path, 'GPT.INI'), 'w') as gpt:
             gpt.write(gpt_data % old_vers)
-        assert gpo.gpo_get_sysvol_gpt_version(gpo_path)[1] == old_vers, \
-          'gpo_get_sysvol_gpt_version() did not return the expected version'
+        self.assertEquals(gpo.gpo_get_sysvol_gpt_version(gpo_path)[1], old_vers,
+          'gpo_get_sysvol_gpt_version() did not return the expected version')
+
+    def test_check_refresh_gpo_list(self):
+        cache = self.lp.cache_path('gpo_cache')
+        ads = gpo.ADS_STRUCT(self.server, self.lp, self.creds)
+        if ads.connect():
+            gpos = ads.get_gpo_list(self.creds.get_username())
+        check_refresh_gpo_list(self.server, self.lp, self.creds, gpos)
+
+        self.assertTrue(os.path.exists(cache),
+                        'GPO cache %s was not created' % cache)
+
+        guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
+        gpt_ini = os.path.join(cache, 'ADDOM.SAMBA.EXAMPLE.COM/POLICIES',
+                               guid, 'GPT.INI')
+        self.assertTrue(os.path.exists(gpt_ini),
+                        'GPT.INI was not cached for %s' % guid)
+
+    def test_check_refresh_gpo_list_malicious_paths(self):
+        # the path cannot contain ..
+        path = '/usr/local/samba/var/locks/sysvol/../../../../../../root/'
+        self.assertRaises(OSError, check_safe_path, path)
+
+        self.assertEqual(check_safe_path('/etc/passwd'), 'etc/passwd')
+        self.assertEqual(check_safe_path('\\\\etc/\\passwd'), 'etc/passwd')
+
+        # there should be no backslashes used to delineate paths
+        before = 'sysvol/addom.samba.example.com\\Policies/' \
+            '{31B2F340-016D-11D2-945F-00C04FB984F9}\\GPT.INI'
+        after = 'addom.samba.example.com/Policies/' \
+            '{31B2F340-016D-11D2-945F-00C04FB984F9}/GPT.INI'
+        result = check_safe_path(before)
+        self.assertEquals(result, after, 'check_safe_path() didn\'t' \
+            ' correctly convert \\ to /')
+
+    def test_gpt_ext_register(self):
+        this_path = os.path.dirname(os.path.realpath(__file__))
+        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,
+                                    smb_conf=self.lp.configfile,
+                                    machine=True, user=False)
+        self.assertTrue(ret, 'Failed to register a gp ext')
+        gp_exts = list_gp_extensions(self.lp.configfile)
+        self.assertTrue(ext_guid in gp_exts.keys(),
+            'Failed to list gp exts')
+        self.assertEquals(gp_exts[ext_guid]['DllName'], ext_path,
+            'Failed to list gp exts')
+
+        unregister_gp_extension(ext_guid)
+        gp_exts = list_gp_extensions(self.lp.configfile)
+        self.assertTrue(ext_guid not in gp_exts.keys(),
+            'Failed to unregister gp exts')
+
+        self.assertTrue(check_guid(ext_guid), 'Failed to parse valid guid')
+        self.assertFalse(check_guid('AAAAAABBBBBBBCCC'), 'Parsed invalid guid')
+
+        lp, parser = parse_gpext_conf(self.lp.configfile)
+        self.assertTrue(lp and parser, 'parse_gpext_conf() invalid return')
+        parser.add_section('test_section')
+        parser.set('test_section', 'test_var', ext_guid)
+        atomic_write_conf(lp, parser)
+
+        lp, parser = parse_gpext_conf(self.lp.configfile)
+        self.assertTrue('test_section' in parser.sections(),
+            'test_section not found in gpext.conf')
+        self.assertEquals(parser.get('test_section', 'test_var'), ext_guid,
+            'Failed to find test variable in gpext.conf')
+        parser.remove_section('test_section')
+        atomic_write_conf(lp, parser)
 
diff --git a/source4/libcli/pysmb.c b/source4/libcli/pysmb.c
index a53e30b..45ff9a0 100644
--- a/source4/libcli/pysmb.c
+++ b/source4/libcli/pysmb.c
@@ -601,7 +601,7 @@ static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
 	PyObject *py_creds = Py_None;
 	PyObject *py_lp = Py_None;
 	const char *kwnames[] = { "hostname", "service", "creds", "lp",
-				  "ntlmv2_auth", "use_spnego", NULL };
+				  "ntlmv2_auth", "use_spnego", "sign", NULL };
 	const char *hostname = NULL;
 	const char *service = NULL;
 	PyObject *smb;
@@ -612,11 +612,12 @@ static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
 	struct smbcli_session_options session_options;
 	uint8_t ntlmv2_auth = 0xFF;
 	uint8_t use_spnego = 0xFF;
+	PyObject *sign = Py_False;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zz|OObb",
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zz|OObbO",
 					 discard_const_p(char *, kwnames),
 					 &hostname, &service, &py_creds, &py_lp,
-					 &ntlmv2_auth, &use_spnego)) {
+					 &ntlmv2_auth, &use_spnego, &sign)) {
 		return NULL;
 	}
 
@@ -658,6 +659,9 @@ static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
 	if (use_spnego != 0xFF) {
 		options.use_spnego = use_spnego;
 	}
+	if (PyObject_IsTrue(sign)) {
+		options.signing = SMB_SIGNING_REQUIRED;
+	}
 
 	status = do_smb_connect(spdata, spdata, hostname, service,
 				&options,
diff --git a/source4/param/pyparam.c b/source4/param/pyparam.c
index 11257c3..7f69d7b 100644
--- a/source4/param/pyparam.c
+++ b/source4/param/pyparam.c
@@ -381,6 +381,30 @@ static PyObject *py_cache_path(PyObject *self, PyObject *args)
 	return ret;
 }
 
+static PyObject *py_state_path(PyObject *self, PyObject *args)
+{
+	struct loadparm_context *lp_ctx =
+		PyLoadparmContext_AsLoadparmContext(self);
+	char *name = NULL;
+	char *path = NULL;
+	PyObject *ret = NULL;
+
+	if (!PyArg_ParseTuple(args, "s", &name)) {
+		return NULL;
+	}
+
+	path = lpcfg_state_path(NULL, lp_ctx, name);
+	if (!path) {


-- 
Samba Shared Repository



More information about the samba-cvs mailing list