gpo: Apply Group Policy Host Access configuration from VGP
authorDavid Mulder <dmulder@suse.com>
Tue, 23 Feb 2021 18:12:05 +0000 (11:12 -0700)
committerJeremy Allison <jra@samba.org>
Thu, 18 Mar 2021 18:50:28 +0000 (18:50 +0000)
Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
python/samba/vgp_access_ext.py
source4/scripting/bin/samba-gpupdate

index c42b81c9be8c8a89bce848c23d859c9fd5b1ea0a..cdbda991c05edeb96b3415c46e12a0d44ba0b9ea 100644 (file)
 # 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, re
 from samba.gpclass import gp_xml_ext
+from hashlib import blake2b
+from tempfile import NamedTemporaryFile
+from samba.common import get_bytes
+
+intro = '''
+### autogenerated by samba
+#
+# This file is generated by the vgp_access_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.
+#
+
+'''
+
+# Access files in /etc/security/access.d are read in the order of the system
+# locale. Here we number the conf files to ensure they are read in the correct
+# order.
+def select_next_conf(directory):
+    configs = [re.match(r'(\d+)', f) for f in os.listdir(directory)]
+    return max([int(m.group(1)) for m in configs if m]+[0])+1
 
 class vgp_access_ext(gp_xml_ext):
+    def __str__(self):
+        return 'VGP/Unix Settings/Host Access'
+
     def process_group_policy(self, deleted_gpo_list, changed_gpo_list,
                              access='/etc/security/access.d'):
-        pass
+        for guid, settings in deleted_gpo_list:
+            self.gp_db.set_guid(guid)
+            if str(self) in settings:
+                for attribute, access_file in settings[str(self)].items():
+                    if os.path.exists(access_file):
+                        os.unlink(access_file)
+                    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)
+                allow = 'MACHINE/VGP/VTLA/VAS/HostAccessControl/Allow/manifest.xml'
+                path = os.path.join(gpo.file_sys_path, allow)
+                allow_conf = self.parse(path)
+                deny = 'MACHINE/VGP/VTLA/VAS/HostAccessControl/Deny/manifest.xml'
+                path = os.path.join(gpo.file_sys_path, deny)
+                deny_conf = self.parse(path)
+                entries = []
+                if allow_conf:
+                    policy = allow_conf.find('policysetting')
+                    data = policy.find('data')
+                    for listelement in data.findall('listelement'):
+                        adobject = listelement.find('adobject')
+                        name = adobject.find('name').text
+                        domain = adobject.find('domain').text
+                        entries.append('+:%s\\%s:ALL' % (domain, name))
+                if deny_conf:
+                    policy = deny_conf.find('policysetting')
+                    data = policy.find('data')
+                    for listelement in data.findall('listelement'):
+                        adobject = listelement.find('adobject')
+                        name = adobject.find('name').text
+                        domain = adobject.find('domain').text
+                        entries.append('-:%s\\%s:ALL' % (domain, name))
+                if len(entries) == 0:
+                    continue
+                conf_id = select_next_conf(access)
+                access_file = os.path.join(access, '%010d_gp.conf' % conf_id)
+                access_contents = '\n'.join(entries)
+                attribute = blake2b(get_bytes(access_contents)).hexdigest()
+                old_val = self.gp_db.retrieve(str(self), attribute)
+                if old_val is not None:
+                    continue
+                if not os.path.isdir(access):
+                    os.mkdir(access, 0o644)
+                with NamedTemporaryFile(delete=False, dir=access) as f:
+                    with open(f.name, 'w') as w:
+                        w.write(intro)
+                        w.write(access_contents)
+                    os.chmod(f.name, 0o644)
+                    os.rename(f.name, access_file)
+                self.gp_db.store(str(self), attribute, access_file)
+                self.gp_db.commit()
 
     def rsop(self, gpo):
         output = {}
+        if gpo.file_sys_path:
+            self.gp_db.set_guid(gpo.name)
+            allow = 'MACHINE/VGP/VTLA/VAS/HostAccessControl/Allow/manifest.xml'
+            path = os.path.join(gpo.file_sys_path, allow)
+            allow_conf = self.parse(path)
+            deny = 'MACHINE/VGP/VTLA/VAS/HostAccessControl/Deny/manifest.xml'
+            path = os.path.join(gpo.file_sys_path, deny)
+            deny_conf = self.parse(path)
+            entries = []
+            if allow_conf:
+                policy = allow_conf.find('policysetting')
+                data = policy.find('data')
+                for listelement in data.findall('listelement'):
+                    adobject = listelement.find('adobject')
+                    name = adobject.find('name').text
+                    domain = adobject.find('domain').text
+                    if str(self) not in output.keys():
+                        output[str(self)] = []
+                    output[str(self)].append('+:%s\\%s:ALL' % (name, domain))
+            if deny_conf:
+                policy = deny_conf.find('policysetting')
+                data = policy.find('data')
+                for listelement in data.findall('listelement'):
+                    adobject = listelement.find('adobject')
+                    name = adobject.find('name').text
+                    domain = adobject.find('domain').text
+                    if str(self) not in output.keys():
+                        output[str(self)] = []
+                    output[str(self)].append('-:%s\\%s:ALL' % (name, domain))
         return output
index a5f5c81e26f3bcd9c28cac4b3ca75c7e49bdf0a2..ea77294bf5be5f224722613197b549a23fc72fa9 100755 (executable)
@@ -43,6 +43,7 @@ from samba.vgp_openssh_ext import vgp_openssh_ext
 from samba.vgp_motd_ext import vgp_motd_ext
 from samba.vgp_issue_ext import vgp_issue_ext
 from samba.vgp_startup_scripts_ext import vgp_startup_scripts_ext
+from samba.vgp_access_ext import vgp_access_ext
 import logging
 
 if __name__ == "__main__":
@@ -105,6 +106,7 @@ if __name__ == "__main__":
         gp_extensions.append(vgp_motd_ext)
         gp_extensions.append(vgp_issue_ext)
         gp_extensions.append(vgp_startup_scripts_ext)
+        gp_extensions.append(vgp_access_ext)
         gp_extensions.extend(machine_exts)
     elif opts.target == 'User':
         gp_extensions.extend(user_exts)