TODO review after conflicts s4:provision: fix sysvol security_descriptors (let them...
authorStefan Metzmacher <metze@samba.org>
Sat, 1 Dec 2012 15:05:11 +0000 (16:05 +0100)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Feb 2019 10:31:19 +0000 (11:31 +0100)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
python/samba/provision/__init__.py

index ccdc5603584f196244262130d8683571473d9d2b..f73c351539c65a5831d6fde61d32f1c3a69cfeb0 100644 (file)
@@ -74,7 +74,7 @@ from samba.dsdb import (
 )
 from samba.idmap import IDmapDB
 from samba.ms_display_specifiers import read_ms_ldif
-from samba.ntacls import setntacl, getntacl, dsacl2fsacl
+from samba.ntacls import setntacl, getntacl, dsacl2fsacl, fsacl_child_sd
 from samba.ndr import ndr_pack, ndr_unpack
 from samba.provision.backend import (
     FDSBackend,
@@ -1585,19 +1585,19 @@ def fill_samdb(samdb, lp, names, logger, policyguid,
     return samdb
 
 
-SYSVOL_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
-POLICIES_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001301bf;;;PA)"
 SYSVOL_SERVICE = "sysvol"
 
 
-def set_dir_acl(path, acl, lp, domsid, use_ntvfs, passdb, service=SYSVOL_SERVICE):
-    setntacl(lp, path, acl, domsid, use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
+def set_dir_acl(path, self_sd, subfolder_sd, subfile_sd, domsid, lp, use_ntvfs,
+        passdb, service=SYSVOL_SERVICE):
+    setntacl(lp, path, self_sd, domsid, use_ntvfs=use_ntvfs, skip_invalid_chown=True,
+             passdb=passdb, service=service)
     for root, dirs, files in os.walk(path, topdown=False):
         for name in files:
-            setntacl(lp, os.path.join(root, name), acl, domsid,
+            setntacl(lp, os.path.join(root, name), subfile_sd, domsid,
                      use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
         for name in dirs:
-            setntacl(lp, os.path.join(root, name), acl, domsid,
+            setntacl(lp, os.path.join(root, name), subfolder_sd, domsid,
                      use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
 
 
@@ -1615,7 +1615,7 @@ def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs, p
 
     # Set ACL for GPO root folder
     root_policy_path = os.path.join(sysvol, dnsdomain, "Policies")
-    setntacl(lp, root_policy_path, POLICIES_ACL, str(domainsid),
+    setntacl(lp, root_policy_path, POLICIES_FOLDER_SD, str(domainsid),
              use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=SYSVOL_SERVICE)
 
     res = samdb.search(base="CN=Policies,CN=System,%s" %(domaindn),
@@ -1623,13 +1623,26 @@ def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs, p
                        expression="", scope=ldb.SCOPE_ONELEVEL)
 
     for policy in res:
-        acl = ndr_unpack(security.descriptor,
-                         policy["nTSecurityDescriptor"][0]).as_sddl()
-        policy_path = getpolicypath(sysvol, dnsdomain, str(policy["cn"]))
-        set_dir_acl(policy_path, dsacl2fsacl(acl, domainsid), lp,
-                    str(domainsid), use_ntvfs,
-                    passdb=passdb)
+        guid = str(policy["cn"])
+        policy_path = getpolicypath(sysvol, dnsdomain, guid)
 
+        if DEFAULT_POLICY_GUID in guid or DEFAULT_DC_POLICY_GUID in guid:
+            self_sd = SYSVOL_SUBFOLDER_SD
+            sub_folder_sd = SYSVOL_SUBFOLDER_SD
+            sub_file_sd = SYSVOL_SUBFILE_SD
+        else:
+            acl = ndr_unpack(security.descriptor,
+                             str(policy["nTSecurityDescriptor"])).as_sddl()
+            owner_sid = security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS)
+            group_sid = security.dom_sid("%s-%d" % (str(domainsid), security.DOMAIN_RID_USERS))
+            self_sd = dsacl2fsacl(acl, domainsid)
+            sub_folder_sd = fsacl_child_sd(self_sd, domainsid, owner_sid, group_sid, container=True)
+            sub_file_sd = fsacl_child_sd(self_sd, domainsid, owner_sid, group_sid, container=False)
+
+        set_dir_acl(policy_path, self_sd,
+                    sub_folder_sd, sub_file_sd,
+                    str(domainsid), lp, use_ntvfs,
+                    passdb=passdb)
 
 def setsysvolacl(samdb, netlogon, sysvol, uid, gid, domainsid, dnsdomain,
                  domaindn, lp, use_ntvfs):
@@ -1714,24 +1727,25 @@ def setsysvolacl(samdb, netlogon, sysvol, uid, gid, domainsid, dnsdomain,
     session_info = auth.user_session(samdb, lp_ctx=lp, dn=userdn,
                                      session_info_flags=flags)
 
-    def _setntacl(path):
+    def _setntacl(path, acl):
         """A helper to reuse args"""
         return setntacl(
-            lp, path, SYSVOL_ACL, str(domainsid),
+            lp, path, acl, str(domainsid),
             use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=s4_passdb,
             service=SYSVOL_SERVICE, session_info=session_info)
 
-    # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
-    _setntacl(sysvol)
+    # Set the SYSVOL_FOLDER_SD on the sysvol folder and
+    # SYSVOL_SUBFILE_SD on files and SYSVOL_SUBFOLDER_SD on the subfolder (first level)
+    _setntacl(sysvol, SYSVOL_FOLDER_SD)
     for root, dirs, files in os.walk(sysvol, topdown=False):
         for name in files:
             if use_ntvfs and canchown:
                 os.chown(os.path.join(root, name), -1, gid)
-            _setntacl(os.path.join(root, name))
+            _setntacl(os.path.join(root, name), SYSVOL_SUBFILE_SD)
         for name in dirs:
             if use_ntvfs and canchown:
                 os.chown(os.path.join(root, name), -1, gid)
-            _setntacl(os.path.join(root, name))
+            _setntacl(os.path.join(root, name), SYSVOL_SUBFOLDER_SD)
 
     # Set acls on Policy folder and policies folders
     set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs, passdb=s4_passdb)
@@ -1744,11 +1758,11 @@ def acl_type(direct_db_access):
         return "VFS"
 
 
-def check_dir_acl(path, acl, lp, domainsid, direct_db_access):
+def check_dir_acl(path, self_sddl, subfolder_sddl, subfile_sddl, domsid, lp, direct_db_access):
     fsacl = getntacl(lp, path, direct_db_access=direct_db_access, service=SYSVOL_SERVICE)
     fsacl_sddl = fsacl.as_sddl(domainsid)
-    if fsacl_sddl != acl:
-        raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), path, fsacl_sddl, acl))
+    if fsacl_sddl != self_sddl:
+        raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), path, fsacl_sddl, self_sddl))
 
     for root, dirs, files in os.walk(path, topdown=False):
         for name in files:
@@ -1759,8 +1773,8 @@ def check_dir_acl(path, acl, lp, domainsid, direct_db_access):
                                         (acl_type(direct_db_access),
                                          os.path.join(root, name)))
             fsacl_sddl = fsacl.as_sddl(domainsid)
-            if fsacl_sddl != acl:
-                raise ProvisioningError('%s ACL on GPO file %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl_sddl, acl))
+            if fsacl_sddl != subfile_sddl:
+                raise ProvisioningError('%s ACL on GPO file %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl_sddl, subfile_sddl))
 
         for name in dirs:
             fsacl = getntacl(lp, os.path.join(root, name),
@@ -1770,9 +1784,8 @@ def check_dir_acl(path, acl, lp, domainsid, direct_db_access):
                                         % (acl_type(direct_db_access),
                                            os.path.join(root, name)))
             fsacl_sddl = fsacl.as_sddl(domainsid)
-            if fsacl_sddl != acl:
-                raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl_sddl, acl))
-
+            if fsacl_sddl != subfolder_sddl:
+                raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl_sddl, subfolder_sddl))
 
 def check_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp,
                    direct_db_access):
@@ -1794,18 +1807,32 @@ def check_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp,
     if fsacl is None:
         raise ProvisioningError('DB ACL on policy root %s %s not found!' % (acl_type(direct_db_access), root_policy_path))
     fsacl_sddl = fsacl.as_sddl(domainsid)
-    if fsacl_sddl != POLICIES_ACL:
-        raise ProvisioningError('%s ACL on policy root %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), root_policy_path, fsacl_sddl, fsacl))
+    if fsacl_sddl != POLICIES_FOLDER_SD:
+        raise ProvisioningError('%s ACL on policy root %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), root_policy_path, fsacl_sddl, POLICIES_FOLDER_SD))
     res = samdb.search(base="CN=Policies,CN=System,%s" %(domaindn),
                        attrs=["cn", "nTSecurityDescriptor"],
                        expression="", scope=ldb.SCOPE_ONELEVEL)
 
     for policy in res:
-        acl = ndr_unpack(security.descriptor,
-                         policy["nTSecurityDescriptor"][0]).as_sddl()
-        policy_path = getpolicypath(sysvol, dnsdomain, str(policy["cn"]))
-        check_dir_acl(policy_path, dsacl2fsacl(acl, domainsid), lp,
-                      domainsid, direct_db_access)
+        guid = str(policy["cn"])
+        policy_path = getpolicypath(sysvol, dnsdomain, guid)
+
+        if DEFAULT_POLICY_GUID in guid or DEFAULT_DC_POLICY_GUID in guid:
+            self_sd = SYSVOL_SUBFOLDER_SD
+            sub_folder_sd = SYSVOL_SUBFOLDER_SD
+            sub_file_sd = SYSVOL_SUBFILE_SD
+        else:
+            acl = ndr_unpack(security.descriptor,
+                             str(policy["nTSecurityDescriptor"])).as_sddl()
+            owner_sid = security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS)
+            group_sid = security.dom_sid("%s-%d" % (str(domainsid), security.DOMAIN_RID_USERS))
+            self_sd = dsacl2fsacl(acl, domainsid)
+            sub_folder_sd = fsacl_child_sd(self_sd, domainsid, owner_sid, group_sid, container=True)
+            sub_file_sd = fsacl_child_sd(self_sd, domainsid, owner_sid, group_sid, container=False)
+
+        check_dir_acl(policy_path, self_sd,
+                      sub_folder_sd, subfile_sd,
+                      domainsid, lp, direct_db_access)
 
 
 def checksysvolacl(samdb, netlogon, sysvol, domainsid, dnsdomain, domaindn,
@@ -1815,8 +1842,6 @@ def checksysvolacl(samdb, netlogon, sysvol, domainsid, dnsdomain, domaindn,
     :param samdb: An LDB object on the SAM db
     :param netlogon: Physical path for the netlogon folder
     :param sysvol: Physical path for the sysvol folder
-    :param uid: The UID of the "Administrator" user
-    :param gid: The GID of the "Domain adminstrators" group
     :param domainsid: The SID of the domain
     :param dnsdomain: The DNS name of the domain
     :param domaindn: The DN of the domain (ie. DC=...)
@@ -1843,14 +1868,13 @@ def checksysvolacl(samdb, netlogon, sysvol, domainsid, dnsdomain, domaindn,
 
     # Ensure we can read this directly, and via the smbd VFS
     for direct_db_access in [True, False]:
-        # Check the SYSVOL_ACL on the sysvol folder and subfolder (first level)
         for dir_path in [os.path.join(sysvol, dnsdomain), netlogon]:
             fsacl = getntacl(lp, dir_path, direct_db_access=direct_db_access, service=SYSVOL_SERVICE)
             if fsacl is None:
                 raise ProvisioningError('%s ACL on sysvol directory %s not found!' % (acl_type(direct_db_access), dir_path))
             fsacl_sddl = fsacl.as_sddl(domainsid)
-            if fsacl_sddl != SYSVOL_ACL:
-                raise ProvisioningError('%s ACL on sysvol directory %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), dir_path, fsacl_sddl, SYSVOL_ACL))
+            if fsacl_sddl != SYSVOL_SUBFOLDER_ACL:
+                raise ProvisioningError('%s ACL on sysvol directory %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), dir_path, fsacl_sddl, SYSVOL_SUBFOLDER_ACL))
 
         # Check acls on Policy folder and policies folders
         check_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp,