From 0b66bf6512f49e199f08485de84ca2177a191be3 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 25 Jan 2021 08:13:18 -0700 Subject: [PATCH] gpo: Apply Group Policy Files Policy from VGP Signed-off-by: David Mulder Reviewed-by: Jeremy Allison --- python/samba/vgp_files_ext.py | 120 ++++++++++++++++++++++++++- selftest/knownfail.d/gpo | 1 - source4/scripting/bin/samba-gpupdate | 2 + 3 files changed, 119 insertions(+), 4 deletions(-) delete mode 100644 selftest/knownfail.d/gpo diff --git a/python/samba/vgp_files_ext.py b/python/samba/vgp_files_ext.py index afea80be4f1..be1d8c95466 100644 --- a/python/samba/vgp_files_ext.py +++ b/python/samba/vgp_files_ext.py @@ -14,13 +14,127 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import os -from samba.gpclass import gp_xml_ext +import os, pwd, grp +from samba.gpclass import gp_xml_ext, check_safe_path +from tempfile import NamedTemporaryFile +from shutil import copyfile, move +from hashlib import blake2b + +def calc_mode(entry): + mode = 0o000 + for permissions in entry.findall('permissions'): + ptype = permissions.get('type') + if ptype == 'user': + if permissions.find('read') is not None: + mode |= 0o400 + if permissions.find('write') is not None: + mode |= 0o200 + if permissions.find('execute') is not None: + mode |= 0o100 + elif ptype == 'group': + if permissions.find('read') is not None: + mode |= 0o040 + if permissions.find('write') is not None: + mode |= 0o020 + if permissions.find('execute') is not None: + mode |= 0o010 + elif ptype == 'other': + if permissions.find('read') is not None: + mode |= 0o004 + if permissions.find('write') is not None: + mode |= 0o002 + if permissions.find('execute') is not None: + mode |= 0o001 + return mode + +def stat_from_mode(mode): + stat = '-' + for i in range(6, -1, -3): + mask = {0o4: 'r', 0o2: 'w', 0o1: 'x'} + for x in mask.keys(): + if mode & (x << i): + stat += mask[x] + else: + stat += '-' + return stat class vgp_files_ext(gp_xml_ext): + def __str__(self): + return 'VGP/Unix Settings/Sudo Rights' + def process_group_policy(self, deleted_gpo_list, changed_gpo_list): - pass + for guid, settings in deleted_gpo_list: + self.gp_db.set_guid(guid) + if str(self) in settings: + for attribute, _ in settings[str(self)].items(): + if os.path.exists(attribute): + os.unlink(attribute) + self.gp_db.delete(str(self), attribute) + self.gp_db.commit() + + for gpo in changed_gpo_list: + if gpo.file_sys_path: + self.gp_db.set_guid(gpo.name) + xml = 'MACHINE/VGP/VTLA/Unix/Files/manifest.xml' + path = os.path.join(gpo.file_sys_path, xml) + xml_conf = self.parse(path) + if not xml_conf: + continue + policy = xml_conf.find('policysetting') + data = policy.find('data') + for entry in data.findall('file_properties'): + local_path = self.lp.cache_path('gpo_cache') + source = entry.find('source').text + source_file = os.path.join(local_path, + os.path.dirname(check_safe_path(path)).upper(), + source.upper()) + if not os.path.exists(source_file): + self.logger.warn('Source file "%s" does not exist' + % source_file) + continue + source_hash = \ + blake2b(open(source_file, 'rb').read()).hexdigest() + target = entry.find('target').text + user = entry.find('user').text + group = entry.find('group').text + mode = calc_mode(entry) + value = '%s:%s:%s:%d' % (source_hash, user, group, mode) + old_val = self.gp_db.retrieve(str(self), target) + if old_val == value: + continue + if os.path.exists(target): + self.logger.warn('Target file "%s" already exists' + % target) + continue + with NamedTemporaryFile(dir=os.path.dirname(target), + delete=False) as f: + copyfile(source_file, f.name) + os.chown(f.name, pwd.getpwnam(user).pw_uid, + grp.getgrnam(group).gr_gid) + os.chmod(f.name, mode) + move(f.name, target) + self.gp_db.store(str(self), target, value) + self.gp_db.commit() def rsop(self, gpo): output = {} + xml = 'MACHINE/VGP/VTLA/Unix/Files/manifest.xml' + if gpo.file_sys_path: + path = os.path.join(gpo.file_sys_path, xml) + xml_conf = self.parse(path) + if not xml_conf: + return output + policy = xml_conf.find('policysetting') + data = policy.find('data') + for entry in data.findall('file_properties'): + source = entry.find('source').text + target = entry.find('target').text + user = entry.find('user').text + group = entry.find('group').text + mode = calc_mode(entry) + p = '%s\t%s\t%s\t%s -> %s' % \ + (stat_from_mode(mode), user, group, target, source) + if str(self) not in output.keys(): + output[str(self)] = [] + output[str(self)].append(p) return output diff --git a/selftest/knownfail.d/gpo b/selftest/knownfail.d/gpo deleted file mode 100644 index 7f4f59962bc..00000000000 --- a/selftest/knownfail.d/gpo +++ /dev/null @@ -1 +0,0 @@ -^samba.tests.gpo.samba.tests.gpo.GPOTests.test_vgp_files \ No newline at end of file diff --git a/source4/scripting/bin/samba-gpupdate b/source4/scripting/bin/samba-gpupdate index d9b8f421961..e2ed7216ff6 100755 --- a/source4/scripting/bin/samba-gpupdate +++ b/source4/scripting/bin/samba-gpupdate @@ -38,6 +38,7 @@ from samba.vgp_sudoers_ext import vgp_sudoers_ext from samba.gp_smb_conf_ext import gp_smb_conf_ext from samba.gp_msgs_ext import gp_msgs_ext from samba.vgp_symlink_ext import vgp_symlink_ext +from samba.vgp_files_ext import vgp_files_ext import logging if __name__ == "__main__": @@ -95,6 +96,7 @@ if __name__ == "__main__": gp_extensions.append(gp_smb_conf_ext) gp_extensions.append(gp_msgs_ext) gp_extensions.append(vgp_symlink_ext) + gp_extensions.append(vgp_files_ext) gp_extensions.extend(machine_exts) elif opts.target == 'User': gp_extensions.extend(user_exts) -- 2.47.3