From 08dc1aa4cc1a697dd72db6a09a32d1929421fc09 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Jun 2011 11:31:25 +1000 Subject: samba-tool: added attribute normalisation checks this checks that all attributes have the right normalisation, and offers to fix the ones that don't --- source4/scripting/python/samba/netcmd/dbcheck.py | 56 ++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 7af210104c..4eebca3503 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -58,12 +58,46 @@ def empty_attribute(self, dn, attrname): print("Removed empty attribute %s" % attrname) +def normalise_mismatch(self, dn, attrname, values): + '''fix attribute normalisation errors''' + print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) + mod_list = [] + for val in values: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + if len(normalised) != 1: + print("Unable to normalise value '%s'" % val) + mod_list.append((val, '')) + elif (normalised[0] != val): + print("value '%s' should be '%s'" % (val, normalised[0])) + mod_list.append((val, normalised[0])) + if not self.fix: + return + if not confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)): + print("Not fixing attribute %s" % attrname) + return + + m = ldb.Message() + m.dn = dn + for i in range(0, len(mod_list)): + (val, nval) = mod_list[i] + m['value_%u' % i] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + if nval != '': + m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) + + try: + self.samdb.modify(m, controls=["relax:0"], validate=False) + except Exception, msg: + print("Failed to normalise attribute %s : %s" % (attrname, msg)) + return + print("Normalised attribute %s" % attrname) + + def check_object(self, dn): '''check one object''' if self.verbose: print("Checking object %s" % dn) - res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE) + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) if len(res) != 1: print("Object %s disappeared during check" % dn) return @@ -71,11 +105,20 @@ def check_object(self, dn): for attrname in obj: if attrname == 'dn': continue + + # check for empty attributes for val in obj[attrname]: if val == '': empty_attribute(self, dn, attrname) continue + # check for incorrectly normalised attributes + for val in obj[attrname]: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + if len(normalised) != 1 or normalised[0] != val: + normalise_mismatch(self, dn, attrname, obj[attrname]) + break + class cmd_dbcheck(Command): """check local AD database for errors""" @@ -96,11 +139,13 @@ class cmd_dbcheck(Command): help='Fix any errors found'), Option("--yes", dest="yes", default=False, action='store_true', help="don't confirm changes, just do them all"), + Option("--cross-ncs", dest="cross_ncs", default=False, action='store_true', + help="cross naming context boundaries"), Option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print more details of checking"), ] - def run(self, DN=None, verbose=False, fix=False, yes=False, + def run(self, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, scope="SUB", credopts=None, sambaopts=None, versionopts=None): self.lp = sambaopts.get_loadparm() self.creds = credopts.get_credentials(self.lp, fallback_machine=True) @@ -117,7 +162,12 @@ class cmd_dbcheck(Command): raise CommandError("Unknown scope %s" % scope) self.search_scope = scope_map[scope] - res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn']) + controls = [] + if cross_ncs: + controls.append("search_options:1:2") + + res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) + print('Checking %u objects' % len(res)) for object in res: check_object(self, object.dn) print('Checked %u objects' % len(res)) -- cgit