[SCM] Samba Shared Repository - branch master updated
Jeremy Allison
jra at samba.org
Tue Feb 9 21:25:01 UTC 2021
The branch, master has been updated
via d0529682605 samba-tool: Add a gpo command for setting VGP OpenSSH Group Policy
via be8f0d8ddbb samba-tool: Test gpo manage openssh set command
via 3c47a81472b samba-tool: Add a gpo command for listing VGP OpenSSH Group Policy
via 61394e5dd10 samba-tool: Test gpo manage openssh list command
via ddf1cbd3452 gpo: Apply Group Policy OpenSSH settings from VGP
via e9c1cc4e74b gpo: Test Group Policy OpenSSH for VGP
from 6816135a2cd s3 lib system: Change signature of sys_proc_fd_path
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit d052968260582290b3ced8f951d75603f642979d
Author: David Mulder <dmulder at suse.com>
Date: Wed Dec 23 14:52:35 2020 -0700
samba-tool: Add a gpo command for setting VGP OpenSSH 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): Tue Feb 9 21:24:14 UTC 2021 on sn-devel-184
commit be8f0d8ddbb9a145bd171618ef7183b9ed648203
Author: David Mulder <dmulder at suse.com>
Date: Wed Dec 23 14:29:58 2020 -0700
samba-tool: Test gpo manage openssh set command
Signed-off-by: David Mulder <dmulder at suse.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 3c47a81472b71642ef92522a27cbd2c14865bf43
Author: David Mulder <dmulder at suse.com>
Date: Wed Dec 23 14:14:49 2020 -0700
samba-tool: Add a gpo command for listing VGP OpenSSH Group Policy
Signed-off-by: David Mulder <dmulder at suse.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 61394e5dd10112190c4af875eed6fcc071ca3920
Author: David Mulder <dmulder at suse.com>
Date: Wed Dec 23 12:25:11 2020 -0700
samba-tool: Test gpo manage openssh list command
Signed-off-by: David Mulder <dmulder at suse.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit ddf1cbd345237162ac19596ac1db787e0d77de65
Author: David Mulder <dmulder at suse.com>
Date: Thu Nov 5 09:08:26 2020 -0700
gpo: Apply Group Policy OpenSSH settings from VGP
Signed-off-by: David Mulder <dmulder at suse.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit e9c1cc4e74be01c963a704ee9ed9466b1420da6d
Author: David Mulder <dmulder at suse.com>
Date: Wed Nov 4 10:24:26 2020 -0700
gpo: Test Group Policy OpenSSH for VGP
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 | 10 ++
python/samba/netcmd/gpo.py | 194 +++++++++++++++++++++++++++++++++++
python/samba/tests/gpo.py | 67 ++++++++++++
python/samba/tests/samba_tool/gpo.py | 90 ++++++++++++++++
python/samba/vgp_openssh_ext.py | 82 +++++++++++++++
source4/scripting/bin/samba-gpupdate | 2 +
6 files changed, 445 insertions(+)
create mode 100644 python/samba/vgp_openssh_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 4de7602570b..ea1f5f8d0e7 100644
--- a/docs-xml/manpages/samba-tool.8.xml
+++ b/docs-xml/manpages/samba-tool.8.xml
@@ -914,6 +914,16 @@
<para>Remove VGP Files Group Policy from the sysvol</para>
</refsect3>
+<refsect3>
+ <title>gpo manage openssh list</title>
+ <para>List VGP OpenSSH Group Policy from the sysvol</para>
+</refsect3>
+
+<refsect3>
+ <title>gpo manage openssh set</title>
+ <para>Sets a VGP OpenSSH Group Policy to 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 8decbe0a8af..a0629feb4cd 100644
--- a/python/samba/netcmd/gpo.py
+++ b/python/samba/netcmd/gpo.py
@@ -2763,6 +2763,199 @@ class cmd_files(SuperCommand):
subcommands["add"] = cmd_add_files()
subcommands["remove"] = cmd_remove_files()
+class cmd_list_openssh(Command):
+ """List VGP OpenSSH Group Policy from the sysvol
+
+This command lists openssh options from the sysvol that will be applied to winbind clients.
+
+Example:
+samba-tool gpo manage openssh 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\\SshCfg',
+ 'SshD\\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')
+ configfile = data.find('configfile')
+ for configsection in configfile.findall('configsection'):
+ if configsection.find('sectionname').text:
+ continue
+ for kv in configsection.findall('keyvaluepair'):
+ self.outf.write('%s %s\n' % (kv.find('key').text,
+ kv.find('value').text))
+
+class cmd_set_openssh(Command):
+ """Sets a VGP OpenSSH Group Policy to the sysvol
+
+This command sets an openssh setting to the sysvol for applying to winbind
+clients. Not providing a value will unset the policy.
+
+Example:
+samba-tool gpo manage openssh set {31B2F340-016D-11D2-945F-00C04FB984F9} KerberosAuthentication Yes
+ """
+
+ synopsis = "%prog <gpo> <setting> [value] [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", "setting", "value?"]
+
+ def run(self, gpo, setting, value=None, 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\\SshCfg\\SshD'])
+ 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')
+ configfile = data.find('configfile')
+ 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 = 'Configuration File'
+ description = ET.SubElement(policysetting, 'description')
+ description.text = 'Represents Unix configuration file settings'
+ apply_mode = ET.SubElement(policysetting, 'apply_mode')
+ apply_mode.text = 'merge'
+ data = ET.SubElement(policysetting, 'data')
+ configfile = ET.SubElement(data, 'configfile')
+ configsection = ET.SubElement(configfile, 'configsection')
+ ET.SubElement(configsection, 'sectionname')
+ elif e.args[0] == 0xC0000022: # STATUS_ACCESS_DENIED
+ raise CommandError("The authenticated user does "
+ "not have sufficient privileges")
+ else:
+ raise
+
+ if value is not None:
+ for configsection in configfile.findall('configsection'):
+ if configsection.find('sectionname').text:
+ continue # Ignore Quest SSH settings
+ settings = {}
+ for kv in configsection.findall('keyvaluepair'):
+ settings[kv.find('key')] = kv
+ if setting in settings.keys():
+ settings[setting].text = value
+ else:
+ keyvaluepair = ET.SubElement(configsection, 'keyvaluepair')
+ key = ET.SubElement(keyvaluepair, 'key')
+ key.text = setting
+ dvalue = ET.SubElement(keyvaluepair, 'value')
+ dvalue.text = value
+ else:
+ for configsection in configfile.findall('configsection'):
+ if configsection.find('sectionname').text:
+ continue # Ignore Quest SSH settings
+ settings = {}
+ for kv in configsection.findall('keyvaluepair'):
+ settings[kv.find('key').text] = kv
+ if setting in settings.keys():
+ configsection.remove(settings[setting])
+ else:
+ raise CommandError("Cannot remove '%s' because it does " \
+ "not exist" % setting)
+
+ 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_openssh(SuperCommand):
+ """Manage OpenSSH Group Policy Objects"""
+ subcommands = {}
+ subcommands["list"] = cmd_list_openssh()
+ subcommands["set"] = cmd_set_openssh()
+
class cmd_manage(SuperCommand):
"""Manage Group Policy Objects"""
subcommands = {}
@@ -2771,6 +2964,7 @@ class cmd_manage(SuperCommand):
subcommands["smb_conf"] = cmd_smb_conf()
subcommands["symlink"] = cmd_symlink()
subcommands["files"] = cmd_files()
+ subcommands["openssh"] = cmd_openssh()
class cmd_gpo(SuperCommand):
"""Group Policy Object (GPO) management."""
diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py
index a3fdc920907..f2c857a8f26 100644
--- a/python/samba/tests/gpo.py
+++ b/python/samba/tests/gpo.py
@@ -32,6 +32,7 @@ from samba.vgp_symlink_ext import vgp_symlink_ext
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
import logging
from samba.credentials import Credentials
from samba.gp_msgs_ext import gp_msgs_ext
@@ -1034,3 +1035,69 @@ class GPOTests(tests.TestCase):
# Unstage the manifest and source files
unstage_file(manifest)
unstage_file(source_file)
+
+ def test_vgp_openssh(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/SSHCFG/SSHD/MANIFEST.XML')
+ 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_openssh_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.Element('policysetting')
+ stage.append(policysetting)
+ version = etree.Element('version')
+ version.text = '1'
+ policysetting.append(version)
+ data = etree.Element('data')
+ configfile = etree.Element('configfile')
+ configsection = etree.Element('configsection')
+ sectionname = etree.Element('sectionname')
+ configsection.append(sectionname)
+ kvpair = etree.Element('keyvaluepair')
+ key = etree.Element('key')
+ key.text = 'AddressFamily'
+ kvpair.append(key)
+ value = etree.Element('value')
+ value.text = 'inet6'
+ kvpair.append(value)
+ configsection.append(kvpair)
+ configfile.append(configsection)
+ data.append(configfile)
+ policysetting.append(data)
+ ret = stage_file(manifest, etree.tostring(stage))
+ self.assertTrue(ret, 'Could not create the target %s' % manifest)
+
+ # Process all gpos, with temp output directory
+ data = 'AddressFamily inet6'
+ with TemporaryDirectory() as dname:
+ ext.process_group_policy([], gpos, dname)
+ conf = os.listdir(dname)
+ self.assertEquals(len(conf), 1, 'The conf file was not created')
+ gp_cfg = os.path.join(dname, conf[0])
+ self.assertIn(data, open(gp_cfg, 'r').read(),
+ 'The sshd_config 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, [], dname)
+ self.assertFalse(os.path.exists(gp_cfg),
+ 'Unapply failed to cleanup config')
+
+ # Unstage the Registry.pol file
+ unstage_file(manifest)
diff --git a/python/samba/tests/samba_tool/gpo.py b/python/samba/tests/samba_tool/gpo.py
index 05c7f30f0a8..d678a96352b 100644
--- a/python/samba/tests/samba_tool/gpo.py
+++ b/python/samba/tests/samba_tool/gpo.py
@@ -988,6 +988,96 @@ class GpoCmdTestCase(SambaToolCmdTest):
os.environ["PASSWORD"]))
self.assertNotIn(target_file, out, 'The test entry was still found!')
+ def test_vgp_openssh_list(self):
+ lp = LoadParm()
+ lp.load(os.environ['SERVERCONFFILE'])
+ local_path = lp.get('path', 'sysvol')
+ vgp_xml = os.path.join(local_path, lp.get('realm').lower(), 'Policies',
+ self.gpo_guid, 'Machine/VGP/VTLA/SshCfg',
+ 'SshD/manifest.xml')
+
+ stage = etree.Element('vgppolicy')
+ policysetting = etree.SubElement(stage, 'policysetting')
+ pv = etree.SubElement(policysetting, 'version')
+ pv.text = '1'
+ name = etree.SubElement(policysetting, 'name')
+ name.text = 'Configuration File'
+ description = etree.SubElement(policysetting, 'description')
+ description.text = 'Represents Unix configuration file settings'
+ apply_mode = etree.SubElement(policysetting, 'apply_mode')
+ apply_mode.text = 'merge'
+ data = etree.SubElement(policysetting, 'data')
+ configfile = etree.SubElement(data, 'configfile')
+ etree.SubElement(configfile, 'filename')
+ configsection = etree.SubElement(configfile, 'configsection')
+ etree.SubElement(configsection, 'sectionname')
+ opt = etree.SubElement(configsection, 'keyvaluepair')
+ key = etree.SubElement(opt, 'key')
+ key.text = 'KerberosAuthentication'
+ value = etree.SubElement(opt, 'value')
+ value.text = 'Yes'
+ ret = stage_file(vgp_xml, etree.tostring(stage, 'utf-8'))
+ self.assertTrue(ret, 'Could not create the target %s' % vgp_xml)
+
+ openssh = 'KerberosAuthentication Yes'
+ (result, out, err) = self.runsublevelcmd("gpo", ("manage",
+ "openssh", "list"),
+ self.gpo_guid, "-H",
+ "ldap://%s" %
+ os.environ["SERVER"],
+ "-U%s%%%s" %
+ (os.environ["USERNAME"],
+ os.environ["PASSWORD"]))
+ self.assertIn(openssh, out, 'The test entry was not found!')
+
+ # Unstage the manifest.xml file
+ unstage_file(vgp_xml)
+
+ def test_vgp_openssh_set(self):
+ (result, out, err) = self.runsublevelcmd("gpo", ("manage",
+ "openssh", "set"),
+ self.gpo_guid,
+ "KerberosAuthentication",
+ "Yes", "-H",
+ "ldap://%s" %
+ os.environ["SERVER"],
+ "-U%s%%%s" %
+ (os.environ["USERNAME"],
+ os.environ["PASSWORD"]))
+ self.assertCmdSuccess(result, out, err, 'OpenSSH set failed')
+
+ openssh = 'KerberosAuthentication Yes'
+ (result, out, err) = self.runsublevelcmd("gpo", ("manage",
+ "openssh", "list"),
+ self.gpo_guid, "-H",
+ "ldap://%s" %
+ os.environ["SERVER"],
+ "-U%s%%%s" %
+ (os.environ["USERNAME"],
+ os.environ["PASSWORD"]))
+ self.assertIn(openssh, out, 'The test entry was not found!')
+
+ (result, out, err) = self.runsublevelcmd("gpo", ("manage",
+ "openssh", "set"),
+ self.gpo_guid,
+ "KerberosAuthentication", "-H",
+ "ldap://%s" %
+ os.environ["SERVER"],
+ "-U%s%%%s" %
+ (os.environ["USERNAME"],
+ os.environ["PASSWORD"]))
+ self.assertCmdSuccess(result, out, err, 'OpenSSH unset failed')
+
+ (result, out, err) = self.runsublevelcmd("gpo", ("manage",
+ "openssh", "list"),
+ self.gpo_guid, "-H",
+ "ldap://%s" %
+ os.environ["SERVER"],
+ "-U%s%%%s" %
+ (os.environ["USERNAME"],
+ os.environ["PASSWORD"]))
+ self.assertNotIn(openssh, out, 'The test entry was still found!')
+
def setUp(self):
"""set up a temporary GPO to work with"""
super(GpoCmdTestCase, self).setUp()
diff --git a/python/samba/vgp_openssh_ext.py b/python/samba/vgp_openssh_ext.py
new file mode 100644
index 00000000000..488bfa728ae
--- /dev/null
+++ b/python/samba/vgp_openssh_ext.py
@@ -0,0 +1,82 @@
+# vgp_openssh_ext samba group policy
+# Copyright (C) David Mulder <dmulder at 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/>.
+
+import os
+from samba.gpclass import gp_xml_ext
+from base64 import b64encode
+from tempfile import NamedTemporaryFile
+from samba.common import get_bytes, get_string
+
+intro = b'''
+### autogenerated by samba
+#
+# This file is generated by the vgp_openssh_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.
+#
+
+'''
+
+class vgp_openssh_ext(gp_xml_ext):
+ def __str__(self):
+ return 'VGP/Unix Settings/OpenSSH'
+
+ def process_group_policy(self, deleted_gpo_list, changed_gpo_list,
+ cfg_dir='/etc/ssh/sshd_config.d'):
+ for guid, settings in deleted_gpo_list:
+ self.gp_db.set_guid(guid)
+ if str(self) in settings:
+ for attribute, sshd_config in settings[str(self)].items():
+ if os.path.exists(sshd_config):
+ os.unlink(sshd_config)
+ 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/SshCfg/SshD/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')
+ configfile = data.find('configfile')
+ for configsection in configfile.findall('configsection'):
+ if configsection.find('sectionname').text:
+ continue
+ settings = {}
+ for kv in configsection.findall('keyvaluepair'):
+ settings[kv.find('key')] = kv.find('value')
+ attribute = get_string(b64encode(get_bytes(gpo.name) +
+ get_bytes(cfg_dir)))
+ fname = self.gp_db.retrieve(str(self), attribute)
+ if fname and os.path.exists(fname):
+ f = open(fname, 'w')
+ else:
+ f = NamedTemporaryFile(prefix='gp_',
+ delete=False,
+ dir=cfg_dir)
+ f.write(intro)
+ for k, v in settings.items():
+ f.write(b'%s %s\n' % \
+ (get_bytes(k.text), get_bytes(v.text)))
--
Samba Shared Repository
More information about the samba-cvs
mailing list