]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
gpupdate: Test Drive Maps Client Side Extension
authorDavid Mulder <dmulder@samba.org>
Fri, 10 Mar 2023 21:29:24 +0000 (14:29 -0700)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 16 Oct 2023 00:59:32 +0000 (00:59 +0000)
Signed-off-by: David Mulder <dmulder@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/gp/gp_drive_maps_ext.py [new file with mode: 0644]
python/samba/tests/bin/gio [new file with mode: 0755]
python/samba/tests/gpo.py
selftest/knownfail.d/gpo [new file with mode: 0644]

diff --git a/python/samba/gp/gp_drive_maps_ext.py b/python/samba/gp/gp_drive_maps_ext.py
new file mode 100644 (file)
index 0000000..c4ca6ba
--- /dev/null
@@ -0,0 +1,28 @@
+# gp_drive_maps_user_ext samba gpo policy
+# Copyright (C) David Mulder <dmulder@suse.com> 2020
+#
+# 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/>.
+
+from samba.gp.gpclass import gp_xml_ext, gp_misc_applier, drop_privileges
+
+class gp_drive_maps_user_ext(gp_xml_ext, gp_misc_applier):
+    def __str__(self):
+        return 'Preferences/Drives'
+
+    def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
+        pass
+
+    def rsop(self, gpo):
+        output = {}
+        return output
diff --git a/python/samba/tests/bin/gio b/python/samba/tests/bin/gio
new file mode 100755 (executable)
index 0000000..30e31ac
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/python3
+import optparse
+
+if __name__ == "__main__":
+    parser = optparse.OptionParser('gio <cmd> <url> [options]')
+    parser.add_option('--unmount')
+
+    (opts, args) = parser.parse_args()
+
+    assert args[0] == 'mount', 'Unrecognized command `gio %s`' % args[0]
+    assert len(args) == 2, 'Missing url parameter'
index c317bd8d15e4cfab98352ffb2f0fe8d0595f8a7f..d68f11233a6a7d1264e131a2fec4d231f8eac87f 100644 (file)
@@ -50,6 +50,7 @@ from samba.gp.gp_msgs_ext import gp_msgs_ext
 from samba.gp.gp_centrify_sudoers_ext import gp_centrify_sudoers_ext
 from samba.gp.gp_centrify_crontab_ext import gp_centrify_crontab_ext, \
                                              gp_user_centrify_crontab_ext
+from samba.gp.gp_drive_maps_ext import gp_drive_maps_user_ext
 from samba.common import get_bytes
 from samba.dcerpc import preg
 from samba.ndr import ndr_pack
@@ -60,7 +61,7 @@ import hashlib
 from samba.gp_parse.gp_pol import GPPolParser
 from glob import glob
 from configparser import ConfigParser
-from samba.gp.gpclass import get_dc_hostname
+from samba.gp.gpclass import get_dc_hostname, expand_pref_variables
 from samba import Ldb
 import ldb as _ldb
 from samba.auth import system_session
@@ -5009,6 +5010,11 @@ br"""
 </PolFile>
 """
 
+drive_maps_xml = b"""<?xml version="1.0" encoding="utf-8"?>
+<Drives clsid="{8FDDCC1A-0C3C-43cd-A6B4-71A6DF20DA8C}"><Drive clsid="{935D1B74-9CB8-4e3c-9914-7DD559B7A417}" name="A:" status="A:" image="2" changed="2023-03-08 19:23:02" uid="{1641E121-DEF3-418D-A428-2D8DF4749504}" bypassErrors="1"><Properties action="U" thisDrive="NOCHANGE" allDrives="NOCHANGE" userName="" path="\\\\example.com\\test" label="TEST" persistent="1" useLetter="0" letter="A"/></Drive>
+</Drives>
+"""
+
 def days2rel_nttime(val):
     seconds = 60
     minutes = 60
@@ -7829,3 +7835,183 @@ class GPOTests(tests.TestCase):
         # Unstage the Registry.pol files
         unstage_file(reg_pol)
         unstage_file(reg_pol2)
+
+    def test_gp_drive_maps_user_ext(self):
+        local_path = self.lp.cache_path('gpo_cache')
+        guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
+        xml_path = os.path.join(local_path, policies, guid,
+                                'USER/PREFERENCES/DRIVES/DRIVES.XML')
+        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 = gp_drive_maps_user_ext(self.lp, machine_creds,
+                                     os.environ.get('DC_USERNAME'), 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 Drives.xml file with test data
+        ret = stage_file(xml_path, drive_maps_xml)
+        self.assertTrue(ret, 'Could not create the target %s' % xml_path)
+
+        # Process all gpos, intentionally skipping the privilege drop
+        ext.process_group_policy([], gpos)
+        # Dump the fake crontab setup for testing
+        p = Popen(['crontab', '-l'], stdout=PIPE)
+        crontab, _ = p.communicate()
+        entry = b'@hourly gio mount smb://example.com/test'
+        self.assertIn(entry, crontab,
+            'The crontab entry was not installed')
+
+        # Check that a call to gpupdate --rsop also succeeds
+        ret = rsop(self.lp)
+        self.assertEquals(ret, 0, 'gpupdate --rsop failed!')
+
+        # Unstage the Drives.xml
+        unstage_file(xml_path)
+
+        # Modify the policy and ensure it is updated
+        xml_conf = etree.fromstring(drive_maps_xml.strip())
+        drives = xml_conf.findall('Drive')
+        props = drives[0].find('Properties')
+        props.attrib['action'] = 'D'
+        ret = stage_file(xml_path,
+                         etree.tostring(xml_conf, encoding='unicode'))
+        self.assertTrue(ret, 'Could not create the target %s' % xml_path)
+
+        # Process all gpos, intentionally skipping the privilege drop
+        ext.process_group_policy([], gpos)
+        # Dump the fake crontab setup for testing
+        p = Popen(['crontab', '-l'], stdout=PIPE)
+        crontab, _ = p.communicate()
+        self.assertNotIn(entry+b'\n', crontab,
+            'The old crontab entry was not removed')
+        entry = entry + b' --unmount'
+        self.assertIn(entry, crontab,
+            'The crontab entry was not installed')
+
+        # Remove policy
+        gp_db = store.get_gplog(os.environ.get('DC_USERNAME'))
+        del_gpos = get_deleted_gpos_list(gp_db, [])
+        ext.process_group_policy(del_gpos, [])
+        # Dump the fake crontab setup for testing
+        p = Popen(['crontab', '-l'], stdout=PIPE)
+        crontab, _ = p.communicate()
+        self.assertNotIn(entry, crontab,
+                         'Unapply failed to cleanup crontab entry')
+
+        # Unstage the Drives.xml
+        unstage_file(xml_path)
+
+        # Modify the policy to set 'run once', ensure there is no cron entry
+        xml_conf = etree.fromstring(drive_maps_xml.strip())
+        drives = xml_conf.findall('Drive')
+        filters = etree.SubElement(drives[0], 'Filters')
+        etree.SubElement(filters, 'FilterRunOnce')
+        ret = stage_file(xml_path,
+                         etree.tostring(xml_conf, encoding='unicode'))
+        self.assertTrue(ret, 'Could not create the target %s' % xml_path)
+
+        # Process all gpos, intentionally skipping the privilege drop
+        ext.process_group_policy([], gpos)
+        # Dump the fake crontab setup for testing
+        p = Popen(['crontab', '-l'], stdout=PIPE)
+        crontab, _ = p.communicate()
+        entry = b'@hourly gio mount smb://example.com/test'
+        self.assertNotIn(entry, crontab,
+            'The crontab entry was added despite run-once request')
+
+        # Remove policy
+        gp_db = store.get_gplog(os.environ.get('DC_USERNAME'))
+        del_gpos = get_deleted_gpos_list(gp_db, [])
+        ext.process_group_policy(del_gpos, [])
+
+        # Unstage the Drives.xml
+        unstage_file(xml_path)
+
+    def test_expand_pref_variables(self):
+        cache_path = self.lp.cache_path(os.path.join('gpo_cache'))
+        gpt_path = 'TEST'
+        username = 'test_uname'
+        test_vars = { 'AppDataDir': os.path.expanduser('~/.config'),
+                      'ComputerName': self.lp.get('netbios name'),
+                      'DesktopDir': os.path.expanduser('~/Desktop'),
+                      'DomainName': self.lp.get('realm'),
+                      'GptPath': os.path.join(cache_path,
+                                              check_safe_path(gpt_path).upper()),
+                      'LogonDomain': self.lp.get('realm'),
+                      'LogonUser': username,
+                      'SystemDrive': '/',
+                      'TempDir': '/tmp'
+        }
+        for exp_var, val in test_vars.items():
+            self.assertEqual(expand_pref_variables('%%%s%%' % exp_var,
+                                                   gpt_path,
+                                                   self.lp,
+                                                   username),
+                             val, 'Failed to expand variable %s' % exp_var)
+        # With the time variables, we can't test for an exact time, so let's do
+        # simple checks instead.
+        time_vars = ['DateTime', 'DateTimeEx', 'LocalTime',
+                     'LocalTimeEx', 'TimeStamp']
+        for time_var in time_vars:
+            self.assertNotEqual(expand_pref_variables('%%%s%%' % time_var,
+                                                      gpt_path,
+                                                      self.lp,
+                                                      username),
+                                None, 'Failed to expand variable %s' % time_var)
+
+        # Here we test to ensure undefined preference variables cause an error.
+        # The reason for testing these is to ensure we don't apply nonsense
+        # policies when they can't be defined. Also, these tests will fail if
+        # one of these is implemented in the future (forcing us to write a test
+        # anytime these are implemented).
+        undef_vars = ['BinaryComputerSid',
+                      'BinaryUserSid',
+                      'CommonAppdataDir',
+                      'CommonDesktopDir',
+                      'CommonFavoritesDir',
+                      'CommonProgramsDir',
+                      'CommonStartUpDir',
+                      'CurrentProccessId',
+                      'CurrentThreadId',
+                      'FavoritesDir',
+                      'GphPath',
+                      'GroupPolicyVersion',
+                      'LastDriveMapped',
+                      'LastError',
+                      'LastErrorText',
+                      'LdapComputerSid',
+                      'LdapUserSid',
+                      'LogonServer',
+                      'LogonUserSid',
+                      'MacAddress',
+                      'NetPlacesDir',
+                      'OsVersion',
+                      'ProgramFilesDir',
+                      'ProgramsDir',
+                      'RecentDocumentsDir',
+                      'ResultCode',
+                      'ResultText',
+                      'ReversedComputerSid',
+                      'ReversedUserSid',
+                      'SendToDir',
+                      'StartMenuDir',
+                      'StartUpDir',
+                      'SystemDir',
+                      'TraceFile',
+                      'WindowsDir'
+        ]
+        for undef_var in undef_vars:
+            try:
+                expand_pref_variables('%%%s%%' % undef_var, gpt_path, self.lp)
+            except NameError:
+                pass
+            else:
+                self.fail('Undefined variable %s caused no error' % undef_var)
diff --git a/selftest/knownfail.d/gpo b/selftest/knownfail.d/gpo
new file mode 100644 (file)
index 0000000..ae63567
--- /dev/null
@@ -0,0 +1,2 @@
+samba.tests.gpo.samba.tests.gpo.GPOTests.test_gp_drive_maps_user_ext
+samba.tests.gpo.samba.tests.gpo.GPOTests.test_expand_pref_variables