samba-tool dbcheck: Allow dbcheck to correct an nTSecurityDescriptor without an owner...
authorAndrew Bartlett <abartlet@samba.org>
Mon, 11 Feb 2013 03:49:01 +0000 (14:49 +1100)
committerStefan Metzmacher <metze@samba.org>
Mon, 25 Mar 2013 10:34:59 +0000 (11:34 +0100)
This is done by making a modification to the SD, which triggers it to be
filled in if we have the correct session_info established on the DB.

However, we normally want dbcheck running as system, so we wrap
the session_info set around this operation only.

Andrew Bartlett

Reviewed-by: Stefan Metzmacher <metze@samba.org>
python/samba/dbchecker.py

index 39a2b4f35492c0bbc39efcb77aef8d00bc787b3b..d0d0ab384cefa6edc79fda85655af83d055d7ae7 100644 (file)
@@ -26,6 +26,7 @@ from samba.dcerpc import drsblobs
 from samba.common import dsdb_Dn
 from samba.dcerpc import security
 from samba.descriptor import get_wellknown_sds, get_diff_sds
+from samba.auth import system_session, admin_session
 
 
 class dbcheck(object):
@@ -54,6 +55,7 @@ class dbcheck(object):
         self.fix_all_orphaned_backlinks = False
         self.fix_rmd_flags = False
         self.fix_ntsecuritydescriptor = False
+        self.fix_ntsecuritydescriptor_owner_group = False
         self.seize_fsmo_role = False
         self.move_to_lost_and_found = False
         self.fix_instancetype = False
@@ -79,6 +81,9 @@ class dbcheck(object):
                 raise
             pass
 
+        self.system_session_info = system_session()
+        self.admin_session_info = admin_session(None, samdb.get_domain_sid())
+
         res = self.samdb.search(base=self.ntds_dsa, scope=ldb.SCOPE_BASE, attrs=['msDS-hasMasterNCs', 'hasMasterNCs'])
         if "msDS-hasMasterNCs" in res[0]:
             self.write_ncs = res[0]["msDS-hasMasterNCs"]
@@ -780,6 +785,37 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                           "Failed to reset attribute %s" % sd_attr):
             self.report("Fixed attribute '%s' of '%s'\n" % (sd_attr, dn))
 
+    def err_missing_sd_owner(self, dn, sd):
+        '''re-write the SD due to a missing owner or group'''
+        sd_attr = "nTSecurityDescriptor"
+        sd_val = ndr_pack(sd)
+        sd_flags = security.SECINFO_OWNER | security.SECINFO_GROUP
+
+        if not self.confirm_all('Fix missing owner or group in %s on %s?' % (sd_attr, dn), 'fix_ntsecuritydescriptor_owner_group'):
+            self.report('Not fixing missing owner or group %s on %s\n' % (sd_attr, dn))
+            return
+
+        nmsg = ldb.Message()
+        nmsg.dn = dn
+        nmsg[sd_attr] = ldb.MessageElement(sd_val, ldb.FLAG_MOD_REPLACE, sd_attr)
+
+        # By setting the session_info to admin_session_info and
+        # setting the security.SECINFO_OWNER | security.SECINFO_GROUP
+        # flags we cause the descriptor module to set the correct
+        # owner and group on the SD, replacing the None/NULL values
+        # for owner_sid and group_sid currently present.
+        #
+        # The admin_session_info matches that used in provision, and
+        # is the best guess we can make for an existing object that
+        # hasn't had something specifically set.
+        #
+        # This is important for the dns related naming contexts.
+        self.samdb.set_session_info(self.admin_session_info)
+        if self.do_modify(nmsg, ["sd_flags:1:%d" % sd_flags],
+                          "Failed to fix metadata for attribute %s" % sd_attr):
+            self.report("Fixed attribute '%s' of '%s'\n" % (sd_attr, dn))
+        self.samdb.set_session_info(self.system_session_info)
+
     def is_fsmo_role(self, dn):
         if dn == self.samdb.domain_dn:
             return True
@@ -876,6 +912,11 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                     error_count += 1
                     continue
 
+                if sd.owner_sid is None or sd.group_sid is None:
+                    self.err_missing_sd_owner(dn, sd)
+                    error_count += 1
+                    continue
+
                 if self.reset_well_known_acls:
                     try:
                         well_known_sd = self.get_wellknown_sd(dn)