[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Wed Feb 24 22:02:01 UTC 2021


The branch, master has been updated
       via  85d24068265 samba-tool: Add a gpo command for removing VGP Startup Scripts Group Policy
       via  91655e6d713 samba-tool: Test gpo manage script startup remove command
       via  e5efe17246d samba-tool: Add a gpo command for adding VGP Startup Scripts Group Policy
       via  f6a0bd8b913 samba-tool: Test gpo manage script startup add command
       via  d22196117cd samba-tool: Add a gpo command for listing VGP Startup Scripts Group Policy
       via  329b6c397b9 samba-tool: Test gpo manage script startup list command
       via  15cec2ac4d7 gpo: Apply Group Policy Startup Scripts from VGP
       via  b13b2d8c3ec gpo: Test Group Policy VGP Startup Script Policy
      from  e49a0b444ab ldb: remove some 'if PY3's in tests

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


- Log -----------------------------------------------------------------
commit 85d240682655cdcdcac22606178a257ac28d7783
Author: David Mulder <dmulder at suse.com>
Date:   Tue Feb 16 14:12:02 2021 -0700

    samba-tool: Add a gpo command for removing VGP Startup Scripts Group Policy
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Wed Feb 24 22:01:08 UTC 2021 on sn-devel-184

commit 91655e6d713cbd6b555ae43a8468f38ba238387e
Author: David Mulder <dmulder at suse.com>
Date:   Fri Feb 12 14:49:16 2021 -0700

    samba-tool: Test gpo manage script startup remove command
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit e5efe17246d1ef6b1aab84901a98660845a50bb1
Author: David Mulder <dmulder at suse.com>
Date:   Fri Feb 12 14:13:51 2021 -0700

    samba-tool: Add a gpo command for adding VGP Startup Scripts Group Policy
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit f6a0bd8b91302f4c7a9b1392d92bdaafcd1bcebd
Author: David Mulder <dmulder at suse.com>
Date:   Fri Feb 12 08:04:30 2021 -0700

    samba-tool: Test gpo manage script startup add command
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit d22196117cd3f87ca1e3790013909d6e72fdb942
Author: David Mulder <dmulder at suse.com>
Date:   Tue Feb 9 06:16:32 2021 -0700

    samba-tool: Add a gpo command for listing VGP Startup Scripts Group Policy
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 329b6c397b988839d73e18968dbdec855a471877
Author: David Mulder <dmulder at suse.com>
Date:   Mon Feb 8 13:08:02 2021 -0700

    samba-tool: Test gpo manage script startup list command
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 15cec2ac4d7af0fa82c21d0109607aa63c86c15a
Author: David Mulder <dmulder at suse.com>
Date:   Tue Feb 2 12:33:11 2021 -0700

    gpo: Apply Group Policy Startup Scripts from VGP
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit b13b2d8c3ec2a64ee56ce03bc9130b628a4c0fcb
Author: David Mulder <dmulder at suse.com>
Date:   Fri Jan 29 13:34:50 2021 -0700

    gpo: Test Group Policy VGP Startup Script Policy
    
    Signed-off-by: David Mulder <dmulder at suse.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>

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

Summary of changes:
 docs-xml/manpages/samba-tool.8.xml      |  15 ++
 python/samba/netcmd/gpo.py              | 279 ++++++++++++++++++++++++++++++++
 python/samba/tests/gpo.py               | 122 ++++++++++++++
 python/samba/tests/samba_tool/gpo.py    | 103 ++++++++++++
 python/samba/vgp_startup_scripts_ext.py | 124 ++++++++++++++
 5 files changed, 643 insertions(+)
 create mode 100644 python/samba/vgp_startup_scripts_ext.py


Changeset truncated at 500 lines:

diff --git a/docs-xml/manpages/samba-tool.8.xml b/docs-xml/manpages/samba-tool.8.xml
index e7ac7dd625a..b808c9b2616 100644
--- a/docs-xml/manpages/samba-tool.8.xml
+++ b/docs-xml/manpages/samba-tool.8.xml
@@ -939,6 +939,21 @@
 	<para>Removes a Samba Sudoers Group Policy from the sysvol.</para>
 </refsect3>
 
+<refsect3>
+	<title>gpo manage scripts startup list</title>
+	<para>List VGP Startup Script Group Policy from the sysvol</para>
+</refsect3>
+
+<refsect3>
+	<title>gpo manage scripts startup add</title>
+	<para>Adds VGP Startup Script Group Policy to the sysvol</para>
+</refsect3>
+
+<refsect3>
+	<title>gpo manage scripts startup remove</title>
+	<para>Removes VGP Startup Script Group Policy from the sysvol</para>
+</refsect3>
+
 <refsect2>
 	<title>group</title>
 	<para>Manage groups.</para>
diff --git a/python/samba/netcmd/gpo.py b/python/samba/netcmd/gpo.py
index 24ecf664ecf..2928ebcf7ce 100644
--- a/python/samba/netcmd/gpo.py
+++ b/python/samba/netcmd/gpo.py
@@ -69,6 +69,7 @@ from samba.common import get_bytes, get_string
 from configparser import ConfigParser
 from io import StringIO, BytesIO
 from samba.vgp_files_ext import calc_mode, stat_from_mode
+import hashlib
 
 
 def gpo_flags_string(value):
@@ -3039,6 +3040,283 @@ class cmd_openssh(SuperCommand):
     subcommands["list"] = cmd_list_openssh()
     subcommands["set"] = cmd_set_openssh()
 
+class cmd_list_startup(Command):
+    """List VGP Startup Script Group Policy from the sysvol
+
+This command lists the startup script policies currently set on the sysvol.
+
+Example:
+samba-tool gpo manage scripts startup list {31B2F340-016D-11D2-945F-00C04FB984F9}
+    """
+
+    synopsis = "%prog <gpo> [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server", type=str,
+                metavar="URL", dest="H"),
+    ]
+
+    takes_args = ["gpo"]
+
+    def run(self, gpo, H=None, sambaopts=None, credopts=None, versionopts=None):
+        self.lp = sambaopts.get_loadparm()
+        self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
+
+        # We need to know writable DC to setup SMB connection
+        if H and H.startswith('ldap://'):
+            dc_hostname = H[7:]
+            self.url = H
+        else:
+            dc_hostname = netcmd_finddc(self.lp, self.creds)
+            self.url = dc_url(self.lp, self.creds, dc=dc_hostname)
+
+        # SMB connect to DC
+        conn = smb_connection(dc_hostname,
+                              'sysvol',
+                              lp=self.lp,
+                              creds=self.creds)
+
+        realm = self.lp.get('realm')
+        vgp_xml = '\\'.join([realm.lower(), 'Policies', gpo,
+                                'MACHINE\\VGP\\VTLA\\Unix',
+                                'Scripts\\Startup\\manifest.xml'])
+        try:
+            xml_data = ET.fromstring(conn.loadfile(vgp_xml))
+        except NTSTATUSError as e:
+            # STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_NOT_FOUND,
+            # STATUS_OBJECT_PATH_NOT_FOUND
+            if e.args[0] in [0xC0000033, 0xC0000034, 0xC000003A]:
+                return # The file doesn't exist, so there is nothing to list
+            if e.args[0] == 0xC0000022: # STATUS_ACCESS_DENIED
+                raise CommandError("The authenticated user does "
+                                   "not have sufficient privileges")
+            raise
+
+        policy = xml_data.find('policysetting')
+        data = policy.find('data')
+        for listelement in data.findall('listelement'):
+            script = listelement.find('script')
+            script_path = '\\'.join(['\\', realm.lower(), 'Policies', gpo,
+                                     'MACHINE\\VGP\\VTLA\\Unix\\Scripts',
+                                     'Startup', script.text])
+            parameters = listelement.find('parameters')
+            run_as = listelement.find('run_as')
+            if run_as is not None:
+                run_as = run_as.text
+            else:
+                run_as = 'root'
+            self.outf.write('@reboot %s %s %s' % (run_as, script_path,
+                                                  parameters.text))
+
+class cmd_add_startup(Command):
+    """Adds VGP Startup Script Group Policy to the sysvol
+
+This command adds a startup script policy to the sysvol.
+
+Example:
+samba-tool gpo manage scripts startup add {31B2F340-016D-11D2-945F-00C04FB984F9} test_script.sh '-n'
+    """
+
+    synopsis = "%prog <gpo> <script> [args] [run_as] [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server", type=str,
+                metavar="URL", dest="H"),
+        Option("--run-once", dest="run_once", default=False, action='store_true',
+               help="Whether to run the script only once"),
+    ]
+
+    takes_args = ["gpo", "script", "args?", "run_as?"]
+
+    def run(self, gpo, script, args=None, run_as=None, run_once=None,
+            H=None, sambaopts=None, credopts=None, versionopts=None):
+        self.lp = sambaopts.get_loadparm()
+        self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
+
+        if not os.path.exists(script):
+            raise CommandError("Script '%s' does not exist" % script)
+
+        # We need to know writable DC to setup SMB connection
+        if H and H.startswith('ldap://'):
+            dc_hostname = H[7:]
+            self.url = H
+        else:
+            dc_hostname = netcmd_finddc(self.lp, self.creds)
+            self.url = dc_url(self.lp, self.creds, dc=dc_hostname)
+
+        # SMB connect to DC
+        conn = smb_connection(dc_hostname,
+                              'sysvol',
+                              lp=self.lp,
+                              creds=self.creds)
+
+        realm = self.lp.get('realm')
+        vgp_dir = '\\'.join([realm.lower(), 'Policies', gpo,
+                             'MACHINE\\VGP\\VTLA\\Unix\\Scripts\\Startup'])
+        vgp_xml = '\\'.join([vgp_dir, 'manifest.xml'])
+        try:
+            xml_data = ET.ElementTree(ET.fromstring(conn.loadfile(vgp_xml)))
+            policy = xml_data.getroot().find('policysetting')
+            data = policy.find('data')
+        except NTSTATUSError as e:
+            # STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_NOT_FOUND,
+            # STATUS_OBJECT_PATH_NOT_FOUND
+            if e.args[0] in [0xC0000033, 0xC0000034, 0xC000003A]:
+                # The file doesn't exist, so create the xml structure
+                xml_data = ET.ElementTree(ET.Element('vgppolicy'))
+                policysetting = ET.SubElement(xml_data.getroot(),
+                                              'policysetting')
+                pv = ET.SubElement(policysetting, 'version')
+                pv.text = '1'
+                name = ET.SubElement(policysetting, 'name')
+                name.text = 'Unix Scripts'
+                description = ET.SubElement(policysetting, 'description')
+                description.text = \
+                    'Represents Unix scripts to run on Group Policy clients'
+                data = ET.SubElement(policysetting, 'data')
+            elif e.args[0] == 0xC0000022: # STATUS_ACCESS_DENIED
+                raise CommandError("The authenticated user does "
+                                   "not have sufficient privileges")
+            else:
+                raise
+
+        script_data = open(script, 'rb').read()
+        listelement = ET.SubElement(data, 'listelement')
+        script_elm = ET.SubElement(listelement, 'script')
+        script_elm.text = os.path.basename(script)
+        hash = ET.SubElement(listelement, 'hash')
+        hash.text = hashlib.md5(script_data).hexdigest().upper()
+        if args is not None:
+            parameters = ET.SubElement(listelement, 'parameters')
+            parameters.text = args.strip('"').strip("'")
+        if run_as is not None:
+            run_as_elm = ET.SubElement(listelement, 'run_as')
+            run_as_elm.text = run_as
+        if run_once is not None:
+            ET.SubElement(listelement, 'run_once')
+
+        out = BytesIO()
+        xml_data.write(out, encoding='UTF-8', xml_declaration=True)
+        out.seek(0)
+        sysvol_script = '\\'.join([vgp_dir, os.path.basename(script)])
+        try:
+            create_directory_hier(conn, vgp_dir)
+            conn.savefile(vgp_xml, out.read())
+            conn.savefile(sysvol_script, script_data)
+        except NTSTATUSError as e:
+            if e.args[0] == 0xC0000022: # STATUS_ACCESS_DENIED
+                raise CommandError("The authenticated user does "
+                                   "not have sufficient privileges")
+            raise
+
+class cmd_remove_startup(Command):
+    """Removes VGP Startup Script Group Policy from the sysvol
+
+This command removes a startup script policy from the sysvol.
+
+Example:
+samba-tool gpo manage scripts startup remove {31B2F340-016D-11D2-945F-00C04FB984F9} test_script.sh
+    """
+
+    synopsis = "%prog <gpo> <script> [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server", type=str,
+                metavar="URL", dest="H"),
+    ]
+
+    takes_args = ["gpo", "script"]
+
+    def run(self, gpo, script, H=None, sambaopts=None, credopts=None,
+            versionopts=None):
+        self.lp = sambaopts.get_loadparm()
+        self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
+
+        # We need to know writable DC to setup SMB connection
+        if H and H.startswith('ldap://'):
+            dc_hostname = H[7:]
+            self.url = H
+        else:
+            dc_hostname = netcmd_finddc(self.lp, self.creds)
+            self.url = dc_url(self.lp, self.creds, dc=dc_hostname)
+
+        # SMB connect to DC
+        conn = smb_connection(dc_hostname,
+                              'sysvol',
+                              lp=self.lp,
+                              creds=self.creds)
+
+        realm = self.lp.get('realm')
+        vgp_dir = '\\'.join([realm.lower(), 'Policies', gpo,
+                             'MACHINE\\VGP\\VTLA\\Unix\\Scripts\\Startup'])
+        vgp_xml = '\\'.join([vgp_dir, 'manifest.xml'])
+        try:
+            xml_data = ET.ElementTree(ET.fromstring(conn.loadfile(vgp_xml)))
+            policy = xml_data.getroot().find('policysetting')
+            data = policy.find('data')
+        except NTSTATUSError as e:
+            # STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_NOT_FOUND,
+            # STATUS_OBJECT_PATH_NOT_FOUND
+            if e.args[0] in [0xC0000033, 0xC0000034, 0xC000003A]:
+                raise CommandError("Cannot remove script '%s' "
+                    "because it does not exist" % script)
+            elif e.args[0] == 0xC0000022: # STATUS_ACCESS_DENIED
+                raise CommandError("The authenticated user does "
+                                   "not have sufficient privileges")
+            else:
+                raise
+
+        for listelement in data.findall('listelement'):
+            script_elm = listelement.find('script')
+            if script_elm.text == os.path.basename(script.replace('\\', '/')):
+                data.remove(listelement)
+                break
+        else:
+            raise CommandError("Cannot remove script '%s' "
+                "because it does not exist" % script)
+
+        out = BytesIO()
+        xml_data.write(out, encoding='UTF-8', xml_declaration=True)
+        out.seek(0)
+        try:
+            create_directory_hier(conn, vgp_dir)
+            conn.savefile(vgp_xml, out.read())
+        except NTSTATUSError as e:
+            if e.args[0] == 0xC0000022: # STATUS_ACCESS_DENIED
+                raise CommandError("The authenticated user does "
+                                   "not have sufficient privileges")
+            raise
+
+class cmd_startup(SuperCommand):
+    """Manage Startup Scripts Group Policy Objects"""
+    subcommands = {}
+    subcommands["list"] = cmd_list_startup()
+    subcommands["add"] = cmd_add_startup()
+    subcommands["remove"] = cmd_remove_startup()
+
+class cmd_scripts(SuperCommand):
+    """Manage Scripts Group Policy Objects"""
+    subcommands = {}
+    subcommands["startup"] = cmd_startup()
+
 class cmd_manage(SuperCommand):
     """Manage Group Policy Objects"""
     subcommands = {}
@@ -3048,6 +3326,7 @@ class cmd_manage(SuperCommand):
     subcommands["symlink"] = cmd_symlink()
     subcommands["files"] = cmd_files()
     subcommands["openssh"] = cmd_openssh()
+    subcommands["scripts"] = cmd_scripts()
 
 class cmd_gpo(SuperCommand):
     """Group Policy Object (GPO) management."""
diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py
index e3b500868ec..2ff3e5e593e 100644
--- a/python/samba/tests/gpo.py
+++ b/python/samba/tests/gpo.py
@@ -33,6 +33,7 @@ from samba.gpclass import gp_inf_ext
 from samba.gp_smb_conf_ext import gp_smb_conf_ext
 from samba.vgp_files_ext import vgp_files_ext
 from samba.vgp_openssh_ext import vgp_openssh_ext
+from samba.vgp_startup_scripts_ext import vgp_startup_scripts_ext
 import logging
 from samba.credentials import Credentials
 from samba.gp_msgs_ext import gp_msgs_ext
@@ -42,6 +43,7 @@ from samba.ndr import ndr_pack
 import codecs
 from shutil import copyfile
 import xml.etree.ElementTree as etree
+import hashlib
 
 realm = os.environ.get('REALM')
 policies = realm + '/POLICIES'
@@ -1106,3 +1108,123 @@ class GPOTests(tests.TestCase):
 
         # Unstage the Registry.pol file
         unstage_file(manifest)
+
+    def test_vgp_startup_scripts(self):
+        local_path = self.lp.cache_path('gpo_cache')
+        guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
+        manifest = os.path.join(local_path, policies, guid, 'MACHINE',
+            'VGP/VTLA/UNIX/SCRIPTS/STARTUP/MANIFEST.XML')
+        test_script = os.path.join(os.path.dirname(manifest), 'TEST.SH')
+        test_data = '#!/bin/sh\necho $@ hello world'
+        ret = stage_file(test_script, test_data)
+        self.assertTrue(ret, 'Could not create the target %s' % test_script)
+        logger = logging.getLogger('gpo_tests')
+        cache_dir = self.lp.get('cache directory')
+        store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
+
+        machine_creds = Credentials()
+        machine_creds.guess(self.lp)
+        machine_creds.set_machine_account()
+
+        # Initialize the group policy extension
+        ext = vgp_startup_scripts_ext(logger, self.lp, machine_creds, store)
+
+        ads = gpo.ADS_STRUCT(self.server, self.lp, machine_creds)
+        if ads.connect():
+            gpos = ads.get_gpo_list(machine_creds.get_username())
+
+        # Stage the manifest.xml file with test data
+        stage = etree.Element('vgppolicy')
+        policysetting = etree.SubElement(stage, 'policysetting')
+        version = etree.SubElement(policysetting, 'version')
+        version.text = '1'
+        data = etree.SubElement(policysetting, 'data')
+        listelement = etree.SubElement(data, 'listelement')
+        script = etree.SubElement(listelement, 'script')
+        script.text = os.path.basename(test_script).lower()
+        parameters = etree.SubElement(listelement, 'parameters')
+        parameters.text = '-n'
+        hash = etree.SubElement(listelement, 'hash')
+        hash.text = \
+            hashlib.md5(open(test_script, 'rb').read()).hexdigest().upper()
+        run_as = etree.SubElement(listelement, 'run_as')
+        run_as.text = 'root'
+        ret = stage_file(manifest, etree.tostring(stage))
+        self.assertTrue(ret, 'Could not create the target %s' % manifest)
+
+        # Process all gpos, with temp output directory
+        with TemporaryDirectory() as dname:
+            ext.process_group_policy([], gpos, dname)
+            files = os.listdir(dname)
+            self.assertEquals(len(files), 1,
+                              'The target script was not created')
+            entry = '@reboot %s %s %s' % (run_as.text, test_script,
+                                          parameters.text)
+            self.assertIn(entry,
+                          open(os.path.join(dname, files[0]), 'r').read(),
+                          'The test entry was not found')
+
+            # Remove policy
+            gp_db = store.get_gplog(machine_creds.get_username())
+            del_gpos = get_deleted_gpos_list(gp_db, [])
+            ext.process_group_policy(del_gpos, [])
+            files = os.listdir(dname)
+            self.assertEquals(len(files), 0,
+                              'The target script was not removed')
+
+            # Test rsop
+            g = [g for g in gpos if g.name == guid][0]
+            ret = ext.rsop(g)
+            self.assertIn(entry, list(ret.values())[0][0],
+                          'The target entry was not listed by rsop')
+
+        # Unstage the manifest.xml and script files
+        unstage_file(manifest)
+        unstage_file(test_script)
+
+        # Stage the manifest.xml file for run once scripts
+        etree.SubElement(listelement, 'run_once')
+        run_as.text = pwd.getpwuid(os.getuid()).pw_name
+        ret = stage_file(manifest, etree.tostring(stage))
+        self.assertTrue(ret, 'Could not create the target %s' % manifest)
+
+        # Process all gpos, with temp output directory
+        # A run once script will be executed immediately,
+        # instead of creating a cron job
+        with TemporaryDirectory() as dname:
+            test_file = '%s/TESTING.txt' % dname
+            test_data = '#!/bin/sh\ntouch %s' % test_file
+            ret = stage_file(test_script, test_data)
+            self.assertTrue(ret, 'Could not create the target %s' % test_script)
+
+            ext.process_group_policy([], gpos, dname)
+            files = os.listdir(dname)
+            self.assertEquals(len(files), 1,
+                              'The test file was not created')
+            self.assertEquals(files[0], os.path.basename(test_file),
+                              'The test file was not created')
+
+            # Unlink the test file and ensure that processing
+            # policy again does not recreate it.
+            os.unlink(test_file)
+            ext.process_group_policy([], gpos, dname)
+            files = os.listdir(dname)
+            self.assertEquals(len(files), 0,
+                              'The test file should not have been created')
+
+            # Remove policy
+            gp_db = store.get_gplog(machine_creds.get_username())
+            del_gpos = get_deleted_gpos_list(gp_db, [])
+            ext.process_group_policy(del_gpos, [])
+
+            # Test rsop
+            entry = 'Run once as: %s `%s %s`' % (run_as.text, test_script,
+                                            parameters.text)
+            g = [g for g in gpos if g.name == guid][0]
+            ret = ext.rsop(g)
+            self.assertIn(entry, list(ret.values())[0][0],
+                          'The target entry was not listed by rsop')
+
+        # Unstage the manifest.xml and script files
+        unstage_file(manifest)
+        unstage_file(test_script)
diff --git a/python/samba/tests/samba_tool/gpo.py b/python/samba/tests/samba_tool/gpo.py
index c57c6786d79..13734f3b163 100644
--- a/python/samba/tests/samba_tool/gpo.py
+++ b/python/samba/tests/samba_tool/gpo.py
@@ -32,6 +32,8 @@ from samba.common import get_string
 from configparser import ConfigParser
 from io import StringIO
 import xml.etree.ElementTree as etree
+from tempfile import NamedTemporaryFile
+from time import sleep
 
 source_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../.."))
 
@@ -1120,6 +1122,107 @@ class GpoCmdTestCase(SambaToolCmdTest):
                                                  os.environ["PASSWORD"]))
         self.assertNotIn(openssh, out, 'The test entry was still found!')
 
+    def test_startup_script_add(self):
+        lp = LoadParm()
+        fname = None
+        with NamedTemporaryFile() as f:
+            fname = os.path.basename(f.name)
+            f.write(b'#!/bin/sh\necho $@ hello world')
+            f.flush()
+            (result, out, err) = self.runsublevelcmd("gpo", ("manage",
+                                                     "scripts", "startup",


-- 
Samba Shared Repository



More information about the samba-cvs mailing list