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 <dmul...@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 <dmul...@suse.com>
    Reviewed-by: Jeremy Allison <j...@samba.org>
    
    Autobuild-User(master): Jeremy Allison <j...@samba.org>
    Autobuild-Date(master): Tue Feb  9 21:24:14 UTC 2021 on sn-devel-184

commit be8f0d8ddbb9a145bd171618ef7183b9ed648203
Author: David Mulder <dmul...@suse.com>
Date:   Wed Dec 23 14:29:58 2020 -0700

    samba-tool: Test gpo manage openssh set command
    
    Signed-off-by: David Mulder <dmul...@suse.com>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 3c47a81472b71642ef92522a27cbd2c14865bf43
Author: David Mulder <dmul...@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 <dmul...@suse.com>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 61394e5dd10112190c4af875eed6fcc071ca3920
Author: David Mulder <dmul...@suse.com>
Date:   Wed Dec 23 12:25:11 2020 -0700

    samba-tool: Test gpo manage openssh list command
    
    Signed-off-by: David Mulder <dmul...@suse.com>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit ddf1cbd345237162ac19596ac1db787e0d77de65
Author: David Mulder <dmul...@suse.com>
Date:   Thu Nov 5 09:08:26 2020 -0700

    gpo: Apply Group Policy OpenSSH settings from VGP
    
    Signed-off-by: David Mulder <dmul...@suse.com>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit e9c1cc4e74be01c963a704ee9ed9466b1420da6d
Author: David Mulder <dmul...@suse.com>
Date:   Wed Nov 4 10:24:26 2020 -0700

    gpo: Test Group Policy OpenSSH for VGP
    
    Signed-off-by: David Mulder <dmul...@suse.com>
    Reviewed-by: Jeremy Allison <j...@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 <dmul...@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

Reply via email to