From 61fc7f285eee888e3603afd7beafba83cca4e378 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Thu, 7 Jul 2011 00:31:21 +0400 Subject: [PATCH] s4-samba-tool: dbcheck, check and fix broken metadata Signed-off-by: Andrew Tridgell --- source4/scripting/python/samba/dbchecker.py | 77 +++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py index eea9dfc28ef..cad3660ef10 100644 --- a/source4/scripting/python/samba/dbchecker.py +++ b/source4/scripting/python/samba/dbchecker.py @@ -3,6 +3,7 @@ # Samba4 AD database checker # # Copyright (C) Andrew Tridgell 2011 +# Copyright (C) Matthieu Patou 2011 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,6 +23,8 @@ import ldb from samba import dsdb from samba import common from samba.dcerpc import misc +from samba.ndr import ndr_unpack +from samba.dcerpc import drsblobs class dsdb_DN(object): @@ -52,6 +55,7 @@ class dbcheck(object): def __init__(self, samdb, samdb_schema=None, verbose=False, fix=False, yes=False, quiet=False): self.samdb = samdb + self.dict_oid_name = None self.samdb_schema = (samdb_schema or samdb) self.verbose = verbose self.fix = fix @@ -324,6 +328,45 @@ class dbcheck(object): return error_count + def process_metadata(self, val): + '''Read metadata properties and list attributes in it''' + + list_att = [] + d = {} + if self.dict_oid_name == None: + res = self.samdb.search(expression = '(lDAPDisplayName=*)', + controls=["search_options:1:2"], + attrs=["attributeID","lDAPDisplayName"]) + for m in res: + d[str(m.get("attributeID"))] = str(m.get("lDAPDisplayName")) + self.dict_oid_name = d + + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,str(val)) + obj = repl.ctr + + for o in repl.ctr.array: + att = self.dict_oid_name[self.samdb.get_oid_from_attid(o.attid)] + list_att.append(att.lower()) + + return list_att + + + def fix_metadata(self, dn, list): + res = self.samdb.search(base = dn, scope=ldb.SCOPE_BASE, attrs = list, + controls = ["search_options:1:2"]) + msg = res[0] + nmsg = ldb.Message() + + delta = self.samdb.msg_diff(nmsg, msg) + nmsg.dn = dn + + for att in delta: + if att == "dn": + continue + val = delta.get(att) + nmsg[att] = ldb.MessageElement(val, ldb.FLAG_MOD_REPLACE, att) + + self.samdb.modify(nmsg, controls = ["relax:0", "provision:0"]) ################################################################ # check one object - calls to individual error handlers above @@ -331,6 +374,9 @@ class dbcheck(object): '''check one object''' if self.verbose: self.report("Checking object %s" % dn) + if '*' in attrs: + attrs.append("replPropertyMetaData") + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1", "show_deleted:1"], attrs=attrs) @@ -339,10 +385,18 @@ class dbcheck(object): return 1 obj = res[0] error_count = 0 + list_attrs_from_md = [] + list_attrs_seen = [] + for attrname in obj: if attrname == 'dn': continue + if str(attrname).lower() == 'replpropertymetadata': + list_attrs_from_md = self.process_metadata(obj[attrname]) + continue + + # check for empty attributes for val in obj[attrname]: if val == '': @@ -359,6 +413,12 @@ class dbcheck(object): error_count += 1 continue + flag = self.samdb_schema.get_systemFlags_from_lDAPDisplayName(attrname) + if (not flag & dsdb.DS_FLAG_ATTR_NOT_REPLICATED + and not flag & dsdb.DS_FLAG_ATTR_IS_CONSTRUCTED + and not self.samdb_schema.get_linkId_from_lDAPDisplayName(attrname)): + list_attrs_seen.append(str(attrname).lower()) + if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_OR_NAME, dsdb.DSDB_SYNTAX_STRING_DN, ldb.LDB_SYNTAX_DN ]: # it's some form of DN, do specialised checking on those @@ -371,4 +431,21 @@ class dbcheck(object): self.err_normalise_mismatch(dn, attrname, obj[attrname]) error_count += 1 break + + show_dn = True + if len(list_attrs_seen): + attrs_to_fix = [] + for att in list_attrs_seen: + if not att in list_attrs_from_md: + if show_dn: + print "On object %s" % dn + show_dn = False + print " Attribute %s not present in replication metadata" % (att) + error_count += 1 + attrs_to_fix.append(att) + + if len(attrs_to_fix) and self.fix: + self.fix_metadata(dn, attrs_to_fix) + + return error_count -- 2.34.1