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>
Tue, 29 Jan 2013 21:03:21 +0000 (22:03 +0100)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
source4/scripting/python/samba/provision/__init__.py

index ea276c7190bcde7d328c41282146bee95bddac29..48c3890d708ab7287fff26cb3aa9e39647192341 100644 (file)
@@ -68,7 +68,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 (
     ExistingBackend,
@@ -1470,19 +1470,21 @@ FILL_FULL = "FULL"
 FILL_SUBDOMAIN = "SUBDOMAIN"
 FILL_NT4SYNC = "NT4SYNC"
 FILL_DRS = "DRS"
-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,
-                    use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
+            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,
-                    use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
+            setntacl(lp, os.path.join(root, name), subfolder_sd, domsid,
+                     use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb,
+                     service=service)
 
 
 def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs, passdb):
@@ -1499,21 +1501,35 @@ 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),
-            use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=SYSVOL_SERVICE)
+    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),
                         attrs=["cn", "nTSecurityDescriptor"],
                         expression="", scope=ldb.SCOPE_ONELEVEL)
 
     for policy in res:
-        acl = ndr_unpack(security.descriptor,
-                         str(policy["nTSecurityDescriptor"])).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):
@@ -1563,23 +1579,23 @@ def setsysvolacl(samdb, netlogon, sysvol, uid, gid, domainsid, dnsdomain,
     else:
         canchown = True
 
-    # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
-    setntacl(lp,sysvol, SYSVOL_ACL, str(domainsid), use_ntvfs=use_ntvfs,
+    setntacl(lp,sysvol, SYSVOL_FOLDER_SD, str(domainsid), use_ntvfs=use_ntvfs,
              skip_invalid_chown=True, passdb=s4_passdb,
              service=SYSVOL_SERVICE)
     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(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid),
-                     use_ntvfs=use_ntvfs, skip_invalid_chown=True,
-                     passdb=s4_passdb, service=SYSVOL_SERVICE)
+            setntacl(lp, os.path.join(root, name), SYSVOL_SUBFILE_SD, str(domainsid),
+                     use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=s4_passdb,
+                     service=SYSVOL_SERVICE)
+
         for name in dirs:
             if use_ntvfs and canchown:
                 os.chown(os.path.join(root, name), -1, gid)
-            setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid),
-                     use_ntvfs=use_ntvfs, skip_invalid_chown=True,
-                     passdb=s4_passdb, service=SYSVOL_SERVICE)
+            setntacl(lp, os.path.join(root, name), SYSVOL_SUBFOLDER_SD, str(domainsid),
+                     use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=s4_passdb,
+                     service=SYSVOL_SERVICE)
 
     # Set acls on Policy folder and policies folders
     set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs, passdb=s4_passdb)
@@ -1590,11 +1606,11 @@ def acl_type(direct_db_access):
     else:
         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:
@@ -1603,8 +1619,8 @@ def check_dir_acl(path, acl, lp, domainsid, direct_db_access):
             if fsacl is None:
                 raise ProvisioningError('%s ACL on GPO file %s %s not found!' % (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),
@@ -1612,9 +1628,8 @@ def check_dir_acl(path, acl, lp, domainsid, direct_db_access):
             if fsacl is None:
                 raise ProvisioningError('%s ACL on GPO directory %s %s not found!' % (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):
@@ -1636,18 +1651,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,
-                         str(policy["nTSecurityDescriptor"])).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,
@@ -1657,8 +1686,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=...)
@@ -1685,14 +1712,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,