The branch, master has been updated via 17ba8120ed6 gpo: Add Centrify Compatible Crontab Extensions via fe0aa82b621 gpo: Test Centrify Compatible Crontab Extensions via d68270eb4b7 gpo: Add Centrify Compatible Sudoers Extension via c28e4396de2 gpo: Test Centrify Compatible Sudoers Extension from 4580fd10468 winbind: send "debug traceid" from winbindd parent to child
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 17ba8120ed61f58d927164d67408399becac27bb Author: David Mulder <dmul...@suse.com> Date: Fri Apr 29 15:21:33 2022 -0600 gpo: Add Centrify Compatible Crontab Extensions Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Tue May 10 20:05:48 UTC 2022 on sn-devel-184 commit fe0aa82b621bf01bbd81186a5ebbae10559facc1 Author: David Mulder <dmul...@suse.com> Date: Fri Apr 29 14:40:41 2022 -0600 gpo: Test Centrify Compatible Crontab Extensions Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> commit d68270eb4b7418327c4f06b46f3686d955831e66 Author: David Mulder <dmul...@suse.com> Date: Fri Apr 29 10:29:01 2022 -0600 gpo: Add Centrify Compatible Sudoers Extension Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> commit c28e4396de27be05c5ba8f96eb9b1e86d01f58ec Author: David Mulder <dmul...@suse.com> Date: Fri Apr 29 09:14:10 2022 -0600 gpo: Test Centrify Compatible Sudoers Extension Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: ...p_scripts_ext.py => gp_centrify_crontab_ext.py} | 68 ++++----- ...p_sudoers_ext.py => gp_centrify_sudoers_ext.py} | 53 +++---- python/samba/tests/gpo.py | 166 +++++++++++++++++++++ source4/scripting/bin/samba-gpupdate | 6 + 4 files changed, 222 insertions(+), 71 deletions(-) copy python/samba/{gp_scripts_ext.py => gp_centrify_crontab_ext.py} (69%) copy python/samba/{gp_sudoers_ext.py => gp_centrify_sudoers_ext.py} (75%) Changeset truncated at 500 lines: diff --git a/python/samba/gp_scripts_ext.py b/python/samba/gp_centrify_crontab_ext.py similarity index 69% copy from python/samba/gp_scripts_ext.py copy to python/samba/gp_centrify_crontab_ext.py index 33049ff6dc0..eace6a973cd 100644 --- a/python/samba/gp_scripts_ext.py +++ b/python/samba/gp_centrify_crontab_ext.py @@ -1,5 +1,5 @@ -# gp_scripts_ext samba gpo policy -# Copyright (C) David Mulder <dmul...@suse.com> 2020 +# gp_centrify_crontab_ext samba gpo policy +# Copyright (C) David Mulder <dmul...@suse.com> 2022 # # 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 @@ -17,14 +17,13 @@ import os, re from subprocess import Popen, PIPE from samba.gpclass import gp_pol_ext, drop_privileges -from base64 import b64encode from hashlib import blake2b from tempfile import NamedTemporaryFile intro = ''' ### autogenerated by samba # -# This file is generated by the gp_scripts_ext Group Policy +# This file is generated by the gp_centrify_crontab_ext Group Policy # Client Side Extension. To modify the contents of this file, # modify the appropriate Group Policy objects which apply # to this machine. DO NOT MODIFY THIS FILE DIRECTLY. @@ -35,11 +34,12 @@ end = ''' ### autogenerated by samba ### ''' -class gp_scripts_ext(gp_pol_ext): +class gp_centrify_crontab_ext(gp_pol_ext): def __str__(self): - return 'Unix Settings/Scripts' + return 'Centrify/CrontabEntries' - def process_group_policy(self, deleted_gpo_list, changed_gpo_list, cdir=None): + def process_group_policy(self, deleted_gpo_list, changed_gpo_list, + cdir=None): for guid, settings in deleted_gpo_list: self.gp_db.set_guid(guid) if str(self) in settings: @@ -51,11 +51,8 @@ class gp_scripts_ext(gp_pol_ext): for gpo in changed_gpo_list: if gpo.file_sys_path: - reg_key = 'Software\\Policies\\Samba\\Unix Settings' - sections = { '%s\\Daily Scripts' % reg_key : '/etc/cron.daily', - '%s\\Monthly Scripts' % reg_key : '/etc/cron.monthly', - '%s\\Weekly Scripts' % reg_key : '/etc/cron.weekly', - '%s\\Hourly Scripts' % reg_key : '/etc/cron.hourly' } + section = \ + 'Software\\Policies\\Centrify\\UnixSettings\\CrontabEntries' self.gp_db.set_guid(gpo.name) pol_file = 'MACHINE/Registry.pol' path = os.path.join(gpo.file_sys_path, pol_file) @@ -63,23 +60,21 @@ class gp_scripts_ext(gp_pol_ext): if not pol_conf: continue for e in pol_conf.entries: - if e.keyname in sections.keys() and e.data.strip(): - cron_dir = sections[e.keyname] if not cdir else cdir - attribute = '%s:%s' % (e.keyname, - b64encode(e.data.encode()).decode()) + if e.keyname == section and e.data.strip(): + cron_dir = '/etc/cron.d' if not cdir else cdir + attribute = blake2b(e.data.encode()).hexdigest() old_val = self.gp_db.retrieve(str(self), attribute) if not old_val: with NamedTemporaryFile(prefix='gp_', mode="w+", delete=False, dir=cron_dir) as f: - contents = '#!/bin/sh\n%s' % intro - contents += '%s\n' % e.data + contents = '%s\n%s\n%s' % (intro, e.data, end) f.write(contents) - os.chmod(f.name, 0o700) self.gp_db.store(str(self), attribute, f.name) self.gp_db.commit() def rsop(self, gpo, target='MACHINE'): output = {} + section = 'Software\\Policies\\Centrify\\UnixSettings\\CrontabEntries' pol_file = '%s/Registry.pol' % target if gpo.file_sys_path: path = os.path.join(gpo.file_sys_path, pol_file) @@ -87,11 +82,10 @@ class gp_scripts_ext(gp_pol_ext): if not pol_conf: return output for e in pol_conf.entries: - key = e.keyname.split('\\')[-1] - if key.endswith('Scripts') and e.data.strip(): - if key not in output.keys(): - output[key] = [] - output[key].append(e.data) + if e.keyname == section and e.data.strip(): + if str(self) not in output.keys(): + output[str(self)] = [] + output[str(self)].append(e.data) return output def fetch_crontab(username): @@ -117,7 +111,7 @@ def install_crontab(fname, username): if p.returncode != 0: raise RuntimeError('Failed to install crontab: %s' % err) -class gp_user_scripts_ext(gp_scripts_ext): +class gp_user_centrify_crontab_ext(gp_centrify_crontab_ext): def process_group_policy(self, deleted_gpo_list, changed_gpo_list): for guid, settings in deleted_gpo_list: self.gp_db.set_guid(guid) @@ -130,7 +124,7 @@ class gp_user_scripts_ext(gp_scripts_ext): with NamedTemporaryFile() as f: if len(entries) > 0: f.write('\n'.join([others, intro, - '\n'.join(entries), end]).encode()) + '\n'.join(entries), end]).encode()) else: f.write(others.encode()) f.flush() @@ -139,11 +133,8 @@ class gp_user_scripts_ext(gp_scripts_ext): for gpo in changed_gpo_list: if gpo.file_sys_path: - reg_key = 'Software\\Policies\\Samba\\Unix Settings' - sections = { '%s\\Daily Scripts' % reg_key : '@daily', - '%s\\Monthly Scripts' % reg_key : '@monthly', - '%s\\Weekly Scripts' % reg_key : '@weekly', - '%s\\Hourly Scripts' % reg_key : '@hourly' } + section = \ + 'Software\\Policies\\Centrify\\UnixSettings\\CrontabEntries' self.gp_db.set_guid(gpo.name) pol_file = 'USER/Registry.pol' path = os.path.join(gpo.file_sys_path, pol_file) @@ -151,21 +142,18 @@ class gp_user_scripts_ext(gp_scripts_ext): if not pol_conf: continue for e in pol_conf.entries: - if e.keyname in sections.keys() and e.data.strip(): - cron_freq = sections[e.keyname] - attribute = '%s:%s' % (e.keyname, - blake2b(e.data.encode()).hexdigest()) + if e.keyname == section and e.data.strip(): + attribute = blake2b(e.data.encode()).hexdigest() old_val = self.gp_db.retrieve(str(self), attribute) - entry = '%s %s' % (cron_freq, e.data) others, entries = fetch_crontab(self.username) - if not old_val or entry not in entries: - entries.append(entry) + if not old_val or e.data not in entries: + entries.append(e.data) with NamedTemporaryFile() as f: f.write('\n'.join([others, intro, - '\n'.join(entries), end]).encode()) + '\n'.join(entries), end]).encode()) f.flush() install_crontab(f.name, self.username) - self.gp_db.store(str(self), attribute, entry) + self.gp_db.store(str(self), attribute, e.data) self.gp_db.commit() def rsop(self, gpo): diff --git a/python/samba/gp_sudoers_ext.py b/python/samba/gp_centrify_sudoers_ext.py similarity index 75% copy from python/samba/gp_sudoers_ext.py copy to python/samba/gp_centrify_sudoers_ext.py index 47e8778d68d..4af51406050 100644 --- a/python/samba/gp_sudoers_ext.py +++ b/python/samba/gp_centrify_sudoers_ext.py @@ -1,5 +1,5 @@ -# gp_sudoers_ext samba gpo policy -# Copyright (C) David Mulder <dmul...@suse.com> 2020 +# gp_centrify_sudoers_ext samba gpo policy +# Copyright (C) David Mulder <dmul...@suse.com> 2022 # # 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 @@ -19,32 +19,19 @@ from samba.gpclass import gp_pol_ext from base64 import b64encode from tempfile import NamedTemporaryFile from subprocess import Popen, PIPE +from samba.gp_sudoers_ext import visudo, intro from samba.gp.util.logging import log -def find_executable(executable, path): - paths = path.split(os.pathsep) - for p in paths: - f = os.path.join(p, executable) - if os.path.isfile(f): - return f - return None +def ext_enabled(entries): + section = 'Software\\Policies\\Centrify\\UnixSettings' + for e in entries: + if e.keyname == section and e.valuename == 'sudo.enabled': + return e.data == 1 + return False -intro = ''' -### autogenerated by samba -# -# This file is generated by the gp_sudoers_ext Group Policy -# Client Side Extension. To modify the contents of this file, -# modify the appropriate Group Policy objects which apply -# to this machine. DO NOT MODIFY THIS FILE DIRECTLY. -# - -''' -visudo = find_executable('visudo', - path='%s:%s' % (os.environ['PATH'], '/usr/sbin')) - -class gp_sudoers_ext(gp_pol_ext): +class gp_centrify_sudoers_ext(gp_pol_ext): def __str__(self): - return 'Unix Settings/Sudo Rights' + return 'Centrify/Sudo Rights' def process_group_policy(self, deleted_gpo_list, changed_gpo_list, sdir='/etc/sudoers.d'): @@ -59,15 +46,17 @@ class gp_sudoers_ext(gp_pol_ext): for gpo in changed_gpo_list: if gpo.file_sys_path: - section = 'Software\\Policies\\Samba\\Unix Settings\\Sudo Rights' + section = 'Software\\Policies\\Centrify\\UnixSettings\\SuDo' self.gp_db.set_guid(gpo.name) pol_file = 'MACHINE/Registry.pol' path = os.path.join(gpo.file_sys_path, pol_file) pol_conf = self.parse(path) - if not pol_conf: + if not pol_conf or not ext_enabled(pol_conf.entries): continue for e in pol_conf.entries: if e.keyname == section and e.data.strip(): + if '**delvals.' in e.valuename: + continue attribute = b64encode(e.data.encode()).decode() old_val = self.gp_db.retrieve(str(self), attribute) if not old_val: @@ -94,6 +83,7 @@ class gp_sudoers_ext(gp_pol_ext): def rsop(self, gpo): output = {} + section = 'Software\\Policies\\Centrify\\UnixSettings\\SuDo' pol_file = 'MACHINE/Registry.pol' if gpo.file_sys_path: path = os.path.join(gpo.file_sys_path, pol_file) @@ -101,9 +91,10 @@ class gp_sudoers_ext(gp_pol_ext): if not pol_conf: return output for e in pol_conf.entries: - key = e.keyname.split('\\')[-1] - if key.endswith('Sudo Rights') and e.data.strip(): - if key not in output.keys(): - output[key] = [] - output[key].append(e.data) + if e.keyname == section and e.data.strip(): + if '**delvals.' in e.valuename: + continue + if str(self) not in output.keys(): + output[str(self)] = [] + output[str(self)].append(e.data) return output diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py index 8d2b3545209..7d3cb878b93 100644 --- a/python/samba/tests/gpo.py +++ b/python/samba/tests/gpo.py @@ -48,6 +48,9 @@ from samba.gp_chromium_ext import gp_chromium_ext from samba.gp_firewalld_ext import gp_firewalld_ext from samba.credentials import Credentials from samba.gp_msgs_ext import gp_msgs_ext +from samba.gp_centrify_sudoers_ext import gp_centrify_sudoers_ext +from samba.gp_centrify_crontab_ext import gp_centrify_crontab_ext, \ + gp_user_centrify_crontab_ext from samba.common import get_bytes from samba.dcerpc import preg from samba.ndr import ndr_pack @@ -9163,3 +9166,166 @@ class GPOTests(tests.TestCase): # Unstage the Registry.pol file unstage_file(reg_pol) + + def test_gp_centrify_sudoers_ext(self): + local_path = self.lp.cache_path('gpo_cache') + guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}' + reg_pol = os.path.join(local_path, policies, guid, + 'MACHINE/REGISTRY.POL') + 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_centrify_sudoers_ext(self.lp, machine_creds, + machine_creds.get_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 Registry.pol file with test data + stage = preg.file() + e1 = preg.entry() + e1.keyname = b'Software\\Policies\\Centrify\\UnixSettings' + e1.valuename = b'sudo.enabled' + e1.type = 4 + e1.data = 1 + e2 = preg.entry() + e2.keyname = b'Software\\Policies\\Centrify\\UnixSettings\\SuDo' + e2.valuename = b'1' + e2.type = 1 + e2.data = b'fakeu ALL=(ALL) NOPASSWD: ALL' + stage.num_entries = 2 + stage.entries = [e1, e2] + ret = stage_file(reg_pol, ndr_pack(stage)) + self.assertTrue(ret, 'Could not create the target %s' % reg_pol) + + # Process all gpos, with temp output directory + with TemporaryDirectory() as dname: + ext.process_group_policy([], gpos, dname) + sudoers = os.listdir(dname) + self.assertEquals(len(sudoers), 1, 'The sudoer file was not created') + self.assertIn(e2.data, + open(os.path.join(dname, sudoers[0]), 'r').read(), + 'The sudoers entry was not applied') + + # 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, []) + self.assertEquals(len(os.listdir(dname)), 0, + 'Unapply failed to cleanup scripts') + + # Unstage the Registry.pol file + unstage_file(reg_pol) + + def test_gp_centrify_crontab_ext(self): + local_path = self.lp.cache_path('gpo_cache') + guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}' + reg_pol = os.path.join(local_path, policies, guid, + 'MACHINE/REGISTRY.POL') + 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_centrify_crontab_ext(self.lp, machine_creds, + machine_creds.get_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 Registry.pol file with test data + stage = preg.file() + e = preg.entry() + e.keyname = \ + b'Software\\Policies\\Centrify\\UnixSettings\\CrontabEntries' + e.valuename = b'Command1' + e.type = 1 + e.data = b'17 * * * * root echo hello world' + stage.num_entries = 1 + stage.entries = [e] + ret = stage_file(reg_pol, ndr_pack(stage)) + self.assertTrue(ret, 'Could not create the target %s' % reg_pol) + + # Process all gpos, with temp output directory + with TemporaryDirectory() as dname: + ext.process_group_policy([], gpos, dname) + cron_entries = os.listdir(dname) + self.assertEquals(len(cron_entries), 1, 'Cron entry not created') + fname = os.path.join(dname, cron_entries[0]) + data = open(fname, 'rb').read() + self.assertIn(get_bytes(e.data), data, 'Cron entry is missing') + + # 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, []) + self.assertEquals(len(os.listdir(dname)), 0, + 'Unapply failed to cleanup script') + + # Unstage the Registry.pol file + unstage_file(reg_pol) + + def test_gp_user_centrify_crontab_ext(self): + local_path = self.lp.cache_path('gpo_cache') + guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}' + reg_pol = os.path.join(local_path, policies, guid, + 'USER/REGISTRY.POL') + 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_user_centrify_crontab_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 Registry.pol file with test data + stage = preg.file() + e = preg.entry() + e.keyname = \ + b'Software\\Policies\\Centrify\\UnixSettings\\CrontabEntries' + e.valuename = b'Command1' + e.type = 1 + e.data = b'17 * * * * echo hello world' + stage.num_entries = 1 + stage.entries = [e] + ret = stage_file(reg_pol, ndr_pack(stage)) + self.assertTrue(ret, 'Could not create the target %s' % reg_pol) + + # 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.assertIn(get_bytes(e.data), 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(get_bytes(e.data), crontab, + 'Unapply failed to cleanup crontab entry') + + # Unstage the Registry.pol file + unstage_file(reg_pol) diff --git a/source4/scripting/bin/samba-gpupdate b/source4/scripting/bin/samba-gpupdate index 0d0e9271a14..079ae485f10 100755 --- a/source4/scripting/bin/samba-gpupdate +++ b/source4/scripting/bin/samba-gpupdate @@ -49,6 +49,9 @@ from samba.gp_cert_auto_enroll_ext import gp_cert_auto_enroll_ext from samba.gp_firefox_ext import gp_firefox_ext from samba.gp_chromium_ext import gp_chromium_ext, gp_chrome_ext from samba.gp_firewalld_ext import gp_firewalld_ext +from samba.gp_centrify_sudoers_ext import gp_centrify_sudoers_ext +from samba.gp_centrify_crontab_ext import gp_centrify_crontab_ext, \ + gp_user_centrify_crontab_ext from samba.credentials import Credentials from samba.gp.util.logging import logger_init @@ -101,6 +104,8 @@ if __name__ == "__main__": gp_extensions.append(gp_scripts_ext) gp_extensions.append(gp_sudoers_ext) gp_extensions.append(vgp_sudoers_ext) + gp_extensions.append(gp_centrify_sudoers_ext) + gp_extensions.append(gp_centrify_crontab_ext) gp_extensions.append(gp_smb_conf_ext) gp_extensions.append(gp_msgs_ext) gp_extensions.append(vgp_symlink_ext) @@ -119,6 +124,7 @@ if __name__ == "__main__": gp_extensions.extend(machine_exts) elif opts.target == 'User': gp_extensions.append(gp_user_scripts_ext) + gp_extensions.append(gp_user_centrify_crontab_ext) gp_extensions.extend(user_exts) if opts.rsop: -- Samba Shared Repository