[SCM] Samba Shared Repository - branch master updated
Stefan Metzmacher
metze at samba.org
Mon Feb 5 17:33:02 UTC 2018
The branch, master has been updated
via 0c3348f dbcheck: skip find_missing_forward_links_from_backlinks() if the db has the sortedLinks feature
via 5bf823d dbcheck: add support for restoring missing forward links
via d59f201 dbcheck: add find_missing_forward_links_from_backlinks()
via 182fb3c dbcheck: make sure we ask for replPropertyMetaData if we need to process any forward link attributes
via 2059803 dbcheck: make sure we always ask for the objectGUID attribute explicitly
via e258b4f dbcheck: add a helper function that checks is a value has duplicate links
via e4cc062 dbcheck: add a dict where we remember attributes with duplicate links
via 44a8782 dbcheck: split out check_duplicate_links from check_dn
via 7df17c0 dbcheck: store fixed forward link attributes with the correct sorting
via b0bc3f6 dbcheck: remove ldb.FLAG_MOD_REPLACE when replacing search results for forward links
via ec433f8 dbcheck: rename err_duplicate_links() to err_recover_forward_links() and adjust the output message
via dc43d31 dbcheck: add link direction to error message for duplicate links
via a651cc7 dbcheck: rename err_duplicate_links arguments
via 9f47fe6 dbcheck: only pass obj_dn to err_orphaned_backlink()
via 6f77503 dbcheck: add forward_syntax argument to err_orphaned_backlink
via 4a71394 dbcheck: rename and reorder err_orphaned_backlink arguments
via 52bd0b0 selftest/dbcheck: add a test for corrupt forward links restoration
via 8c01acd Revert "dbcheck: disable fixing duplicate linked attributes until we can recover lost forward links"
via 55d4665 python/common: add __cmp__ function to dsdb_Dn similar to parsed_dn_compare()
via c56eb49 python:tests: add test_dsdb_Dn_sorted() to "samba.tests.common"
via 1341780 python:tests: remove test_dsdb_Dn() to test_dsdb_Dn_binary()
via 681e0a1 python:tests: use TestCaseInTempDir for "samba.tests.common"
via 28fcf63 python/netcmd: implement __repr__ for class CommandError
from 84f07a8 s3/smbd: fix handling of delete-on-close on directories
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 0c3348feb09f4f0ba85455b8c3ff5c5fa60d139b
Author: Stefan Metzmacher <metze at samba.org>
Date: Wed Jan 31 09:50:47 2018 +0100
dbcheck: skip find_missing_forward_links_from_backlinks() if the db has the sortedLinks feature
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
Autobuild-Date(master): Mon Feb 5 18:32:51 CET 2018 on sn-devel-144
commit 5bf823d68bd33ee3160175a18a3838eff4e3cbb2
Author: Ralph Boehme <slow at samba.org>
Date: Thu Jan 25 14:48:55 2018 +0100
dbcheck: add support for restoring missing forward links
This recovers broken databases with duplicate and missing
forward links.
See commit a25c99c9f1fd1814c56c21848c748cd0e038eed7 for
the fix that prevents to problem from happening.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit d59f201388e8a16688adda145734dab8e27b785f
Author: Ralph Boehme <slow at samba.org>
Date: Thu Jan 25 14:48:55 2018 +0100
dbcheck: add find_missing_forward_links_from_backlinks()
find_missing_forward_links_from_backlinks() finds and returns missing forward-links by
searching all for all objects that link to the object in the backlink attribute.
This will be used in the next commit to restore forward links in a corrupted
forward link attribute by passing the missing backling objects to
err_recover_forward_links().
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit 182fb3c4c9db8715d0dbcbc3d1aa0655b5cb29f1
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 12:19:31 2018 +0100
dbcheck: make sure we ask for replPropertyMetaData if we need to process any forward link attributes
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit 20598033866ca3d0fdad1edf3cb39e4614eae112
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 12:19:31 2018 +0100
dbcheck: make sure we always ask for the objectGUID attribute explicitly
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit e258b4fb281d8577c425e05b35ce05cf128617ea
Author: Ralph Boehme <slow at samba.org>
Date: Wed Jan 24 22:24:15 2018 +0100
dbcheck: add a helper function that checks is a value has duplicate links
Will be used in a subsequent commit.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit e4cc062fa98f65369f3bde24a987c2651632cb06
Author: Ralph Boehme <slow at samba.org>
Date: Thu Jan 25 10:34:29 2018 +0100
dbcheck: add a dict where we remember attributes with duplicate links
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit 44a8782d71676517f0991f279f2472391ecede3b
Author: Ralph Boehme <slow at samba.org>
Date: Wed Jan 24 20:01:27 2018 +0100
dbcheck: split out check_duplicate_links from check_dn
Refactoring, no change in behaviour.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit 7df17c0a8dffceb053ca806c9426d493b4837b1a
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 09:55:21 2018 +0100
dbcheck: store fixed forward link attributes with the correct sorting
The corruption we're trying to fix messed up the sorting,
so there's no point in keeping the current order.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit b0bc3f60084e5998dd34aada2ac7377d390affc6
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 09:39:40 2018 +0100
dbcheck: remove ldb.FLAG_MOD_REPLACE when replacing search results for forward links
Search results don't have an ldb.FLAG_MOD_* flags set.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit ec433f8531a822dd40b343fbf3244157a5ecd544
Author: Ralph Boehme <slow at samba.org>
Date: Thu Jan 25 14:36:52 2018 +0100
dbcheck: rename err_duplicate_links() to err_recover_forward_links() and adjust the output message
It's really a fatal error to have duplicate values as it's very likely that
some forward links got lost.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit dc43d31cd20fd12d2758b73ec0318215b8fbedfb
Author: Ralph Boehme <slow at samba.org>
Date: Thu Jan 25 14:41:58 2018 +0100
dbcheck: add link direction to error message for duplicate links
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit a651cc79d64b9bcc1d5fee9b2ef8800a1579dea1
Author: Ralph Boehme <slow at samba.org>
Date: Wed Jan 24 19:37:55 2018 +0100
dbcheck: rename err_duplicate_links arguments
In preperation of adding more arguments.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 9f47fe6c4a8bde4abfee3c774d9667e6a3439a45
Author: Stefan Metzmacher <metze at samba.org>
Date: Mon Jan 29 22:48:42 2018 +0100
dbcheck: only pass obj_dn to err_orphaned_backlink()
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit 6f77503871fcb815e474cb76d14e22f7a8f083c9
Author: Ralph Boehme <slow at samba.org>
Date: Thu Jan 25 10:52:35 2018 +0100
dbcheck: add forward_syntax argument to err_orphaned_backlink
Will be used in a subsequent commit.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit 4a71394c6a30e8a1b5c6553f7410148dbf2e4a80
Author: Ralph Boehme <slow at samba.org>
Date: Wed Jan 24 19:31:23 2018 +0100
dbcheck: rename and reorder err_orphaned_backlink arguments
In preperation of adding more arguments.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit 52bd0b09804621e6de9ee0a377a442a42e07ee05
Author: Ralph Boehme <slow at samba.org>
Date: Thu Jan 25 21:34:47 2018 +0100
selftest/dbcheck: add a test for corrupt forward links restoration
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 8c01acd56274a5cb5926622cacab997cb62dd5a9
Author: Ralph Boehme <slow at samba.org>
Date: Wed Jan 24 11:34:43 2018 +0100
Revert "dbcheck: disable fixing duplicate linked attributes until we can recover lost forward links"
This reverts commit 43e3f79d54c5aeaea820865d298d4249cf47af99.
The real fix will follow in the next commits.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
commit 55d466549a3113f7625acdd6eb42f71cf63719b5
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 09:51:20 2018 +0100
python/common: add __cmp__ function to dsdb_Dn similar to parsed_dn_compare()
Linked attribute values are sorted by objectGUID of the link target.
For C code we have parsed_dn_compare() to implement the logic,
the same is now available on python dsdb_Dn objects.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit c56eb49119117a1a06afb0a76630ae5c7a1ca30c
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 11:09:55 2018 +0100
python:tests: add test_dsdb_Dn_sorted() to "samba.tests.common"
Failing until dsdb_Dn implements the correct __cmp__() function.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit 1341780dcf9ec0c5d852fbbb77c5e00db2ad6564
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 11:09:40 2018 +0100
python:tests: remove test_dsdb_Dn() to test_dsdb_Dn_binary()
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit 681e0a1745b45c6ac22d394b9e78cb67007d7dc4
Author: Stefan Metzmacher <metze at samba.org>
Date: Tue Jan 30 10:39:30 2018 +0100
python:tests: use TestCaseInTempDir for "samba.tests.common"
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13228
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit 28fcf631c8985e8418fdc67cc78053e503f56d50
Author: Stefan Metzmacher <metze at samba.org>
Date: Wed Jan 24 19:14:53 2018 +0100
python/netcmd: implement __repr__ for class CommandError
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
-----------------------------------------------------------------------
Summary of changes:
python/samba/common.py | 17 ++
python/samba/dbchecker.py | 332 +++++++++++++++++----
python/samba/netcmd/__init__.py | 3 +
python/samba/tests/common.py | 33 +-
selftest/knownfail.d/dbcheck_duplicate_member | 5 -
...ted-after-dbcheck-forward-link-corruption.ldif} | 8 +-
...dbcheck-link-output-forward-link-corruption.txt | 12 +
...pected-dbcheck-link-output_duplicate_member.txt | 5 +-
testprogs/blackbox/dbcheck-links.sh | 78 +++++
9 files changed, 410 insertions(+), 83 deletions(-)
delete mode 100644 selftest/knownfail.d/dbcheck_duplicate_member
copy source4/selftest/provisions/release-4-5-0-pre1/{expected-duplicates-after-link-dbcheck.ldif => expected-after-dbcheck-forward-link-corruption.ldif} (65%)
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output-forward-link-corruption.txt
Changeset truncated at 500 lines:
diff --git a/python/samba/common.py b/python/samba/common.py
index 20f170c..a915934 100644
--- a/python/samba/common.py
+++ b/python/samba/common.py
@@ -19,6 +19,8 @@
import ldb
import dsdb
+from samba.ndr import ndr_pack
+from samba.dcerpc import misc
import binascii
@@ -93,6 +95,21 @@ class dsdb_Dn(object):
def __str__(self):
return self.prefix + str(self.dn.extended_str(mode=1))
+ def __cmp__(self, other):
+ ''' compare dsdb_Dn values similar to parsed_dn_compare()'''
+ dn1 = self
+ dn2 = other
+ guid1 = dn1.dn.get_extended_component("GUID")
+ guid1b = ndr_pack(misc.GUID(guid1))
+ guid2 = dn2.dn.get_extended_component("GUID")
+ guid2b = ndr_pack(misc.GUID(guid2))
+
+ v = cmp(guid1, guid2)
+ if v != 0:
+ return v
+ v = cmp(dn1.binary, dn2.binary)
+ return v
+
def get_binary_integer(self):
'''return binary part of a dsdb_Dn as an integer, or None'''
if self.prefix == '':
diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 6e4c440..b2b8b0c 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -65,7 +65,9 @@ class dbcheck(object):
self.fix_undead_linked_attributes = False
self.fix_all_missing_backlinks = False
self.fix_all_orphaned_backlinks = False
- self.fix_all_duplicate_links = False
+ self.fix_all_missing_forward_links = False
+ self.duplicate_link_cache = dict()
+ self.recover_all_forward_links = False
self.fix_rmd_flags = False
self.fix_ntsecuritydescriptor = False
self.fix_ntsecuritydescriptor_owner_group = False
@@ -184,6 +186,23 @@ class dbcheck(object):
else:
self.rid_set_dn = None
+ self.compatibleFeatures = []
+ self.requiredFeatures = []
+
+ try:
+ res = self.samdb.search(scope=ldb.SCOPE_BASE,
+ base="@SAMBA_DSDB",
+ attrs=["compatibleFeatures",
+ "requiredFeatures"])
+ if "compatibleFeatures" in res[0]:
+ self.compatibleFeatures = res[0]["compatibleFeatures"]
+ if "requiredFeatures" in res[0]:
+ self.requiredFeatures = res[0]["requiredFeatures"]
+ except ldb.LdbError as (enum, estr):
+ if enum != ldb.ERR_NO_SUCH_OBJECT:
+ raise
+ pass
+
def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=[], attrs=['*']):
'''perform a database check, returning the number of errors found'''
res = self.samdb.search(base=DN, scope=scope, attrs=['dn'], controls=controls)
@@ -708,42 +727,44 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
"Failed to fix incorrect RMD_FLAGS %u" % rmd_flags):
self.report("Fixed incorrect RMD_FLAGS %u" % (rmd_flags))
- def err_orphaned_backlink(self, obj, attrname, val, link_name, target_dn, duplicate_links):
+ def err_orphaned_backlink(self, obj_dn, backlink_attr, backlink_val,
+ target_dn, forward_attr, forward_syntax,
+ check_duplicates=True):
'''handle a orphaned backlink value'''
- self.report("ERROR: orphaned backlink attribute '%s' in %s for link %s in %s" % (attrname, obj.dn, link_name, target_dn))
- if duplicate_links:
- self.report("ERROR: FATAL! Most likely the corresponding forward link got lost!")
- self.report("ERROR: FATAL! See https://bugzilla.samba.org/show_bug.cgi?id=13228")
- self.report("Recovery handling will be implemented in a future version")
- self.report("Not removing orphaned backlink %s" % attrname)
+ if check_duplicates is True and self.has_duplicate_links(target_dn, forward_attr, forward_syntax):
+ self.report("WARNING: Keep orphaned backlink attribute " + \
+ "'%s' in '%s' for link '%s' in '%s'" % (
+ backlink_attr, obj_dn, forward_attr, target_dn))
return
- if not self.confirm_all('Remove orphaned backlink %s' % attrname, 'fix_all_orphaned_backlinks'):
- self.report("Not removing orphaned backlink %s" % attrname)
+ self.report("ERROR: orphaned backlink attribute '%s' in %s for link %s in %s" % (backlink_attr, obj_dn, forward_attr, target_dn))
+ if not self.confirm_all('Remove orphaned backlink %s' % backlink_attr, 'fix_all_orphaned_backlinks'):
+ self.report("Not removing orphaned backlink %s" % backlink_attr)
return
m = ldb.Message()
- m.dn = obj.dn
- m['value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname)
+ m.dn = obj_dn
+ m['value'] = ldb.MessageElement(backlink_val, ldb.FLAG_MOD_DELETE, backlink_attr)
if self.do_modify(m, ["show_recycled:1", "relax:0"],
- "Failed to fix orphaned backlink %s" % attrname):
- self.report("Fixed orphaned backlink %s" % (attrname))
+ "Failed to fix orphaned backlink %s" % backlink_attr):
+ self.report("Fixed orphaned backlink %s" % (backlink_attr))
- def err_duplicate_links(self, obj, attrname, vals):
+ def err_recover_forward_links(self, obj, forward_attr, forward_vals):
'''handle a duplicate links value'''
- self.report("ERROR: FATAL! Most likely some forward link values for attribute '%s' in '%s' got lost!" % (attrname, obj.dn))
- self.report("ERROR: FATAL! See https://bugzilla.samba.org/show_bug.cgi?id=13228")
- self.report("Recovery handling will be implemented in a future version")
- self.report("Not removing duplicate links in attribute '%s'" % attrname)
- return
- if not self.confirm_all("Remove duplicate links in attribute '%s'" % attrname, 'fix_all_duplicate_links'):
- self.report("Not removing duplicate links in attribute '%s'" % attrname)
+ self.report("RECHECK: 'Missing/Duplicate/Correct link' lines above for attribute '%s' in '%s'" % (forward_attr, obj.dn))
+
+ if not self.confirm_all("Commit fixes for (missing/duplicate) forward links in attribute '%s'" % forward_attr, 'recover_all_forward_links'):
+ self.report("Not fixing corrupted (missing/duplicate) forward links in attribute '%s' of '%s'" % (
+ forward_attr, obj.dn))
return
m = ldb.Message()
m.dn = obj.dn
- m['value'] = ldb.MessageElement(vals, ldb.FLAG_MOD_REPLACE, attrname)
+ m['value'] = ldb.MessageElement(forward_vals, ldb.FLAG_MOD_REPLACE, forward_attr)
if self.do_modify(m, ["local_oid:1.3.6.1.4.1.7165.4.3.19.2:1"],
- "Failed to fix duplicate links in attribute '%s'" % attrname):
- self.report("Fixed duplicate links in attribute '%s'" % (attrname))
+ "Failed to fix duplicate links in attribute '%s'" % forward_attr):
+ self.report("Fixed duplicate links in attribute '%s'" % (forward_attr))
+ duplicate_cache_key = "%s:%s" % (str(obj.dn), forward_attr)
+ assert duplicate_cache_key in self.duplicate_link_cache
+ self.duplicate_link_cache[duplicate_cache_key] = False
def err_no_fsmoRoleOwner(self, obj):
'''handle a missing fSMORoleOwner'''
@@ -896,30 +917,27 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
return dsdb_dn
return None
- def check_dn(self, obj, attrname, syntax_oid):
- '''check a DN attribute for correctness'''
+ def check_duplicate_links(self, obj, forward_attr, forward_syntax, forward_linkID, backlink_attr):
+ '''check a linked values for duplicate forward links'''
error_count = 0
- obj_guid = obj['objectGUID'][0]
- linkID, reverse_link_name = self.get_attr_linkID_and_reverse_name(attrname)
- if reverse_link_name is not None:
- reverse_syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName(reverse_link_name)
- else:
- reverse_syntax_oid = None
-
- duplicate_links = False
duplicate_dict = dict()
- duplicate_list = list()
unique_dict = dict()
- unique_list = list()
- for val in obj[attrname]:
- if linkID & 1:
- #
- # Only cleanup forward links here,
- # back links are handled below.
- break
- dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid)
+ # Only forward links can have this problem
+ if forward_linkID & 1:
+ # If we got the reverse, skip it
+ return (error_count, duplicate_dict, unique_dict)
+
+ if backlink_attr is None:
+ return (error_count, duplicate_dict, unique_dict)
+
+ duplicate_cache_key = "%s:%s" % (str(obj.dn), forward_attr)
+ if duplicate_cache_key not in self.duplicate_link_cache:
+ self.duplicate_link_cache[duplicate_cache_key] = False
+
+ for val in obj[forward_attr]:
+ dsdb_dn = dsdb_Dn(self.samdb, val, forward_syntax)
# all DNs should have a GUID component
guid = dsdb_dn.dn.get_extended_component("GUID")
@@ -929,14 +947,12 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
keystr = guidstr + dsdb_dn.prefix
if keystr not in unique_dict:
unique_dict[keystr] = dsdb_dn
- unique_list.append(keystr)
continue
error_count += 1
if keystr not in duplicate_dict:
duplicate_dict[keystr] = dict()
duplicate_dict[keystr]["keep"] = None
duplicate_dict[keystr]["delete"] = list()
- duplicate_list.append(keystr)
# Now check for the highest RMD_VERSION
v1 = int(unique_dict[keystr].dn.get_extended_component("RMD_VERSION"))
@@ -961,25 +977,197 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
duplicate_dict[keystr]["delete"].append(unique_dict[keystr])
unique_dict[keystr] = dsdb_dn
- if len(duplicate_list) != 0:
- duplicate_links = True
- self.report("ERROR: FATAL! Most likely some forward link values for attribute '%s' in '%s' got lost!" % (attrname, obj.dn))
- self.report("ERROR: FATAL! See https://bugzilla.samba.org/show_bug.cgi?id=13228")
+ if error_count != 0:
+ self.duplicate_link_cache[duplicate_cache_key] = True
+
+ return (error_count, duplicate_dict, unique_dict)
+
+ def has_duplicate_links(self, dn, forward_attr, forward_syntax):
+ '''check a linked values for duplicate forward links'''
+ error_count = 0
+
+ duplicate_cache_key = "%s:%s" % (str(dn), forward_attr)
+ if duplicate_cache_key in self.duplicate_link_cache:
+ return self.duplicate_link_cache[duplicate_cache_key]
+
+ forward_linkID, backlink_attr = self.get_attr_linkID_and_reverse_name(forward_attr)
+
+ attrs = [forward_attr]
+ controls = ["extended_dn:1:1", "reveal_internals:0"]
+
+ # check its the right GUID
+ try:
+ res = self.samdb.search(base=str(dn), scope=ldb.SCOPE_BASE,
+ attrs=attrs, controls=controls)
+ except ldb.LdbError, (enum, estr):
+ if enum != ldb.ERR_NO_SUCH_OBJECT:
+ raise
+
+ return False
+
+ obj = res[0]
+ error_count, duplicate_dict, unique_dict = \
+ self.check_duplicate_links(obj, forward_attr, forward_syntax, forward_linkID, backlink_attr)
+
+ if duplicate_cache_key in self.duplicate_link_cache:
+ return self.duplicate_link_cache[duplicate_cache_key]
+
+ return False
+
+ def find_missing_forward_links_from_backlinks(self, obj,
+ forward_attr,
+ forward_syntax,
+ backlink_attr,
+ forward_unique_dict):
+ '''Find all backlinks linking to obj_guid_str not already in forward_unique_dict'''
+ missing_forward_links = []
+ error_count = 0
- self.report("ERROR: Duplicate link values for attribute '%s' in '%s'" % (attrname, obj.dn))
- for keystr in duplicate_list:
+ if backlink_attr is None:
+ return (missing_forward_links, error_count)
+
+ if forward_syntax != ldb.SYNTAX_DN:
+ self.report("Not checking for missing forward links for syntax: %s",
+ forward_syntax)
+ return (missing_forward_links, error_count)
+
+ if "sortedLinks" in self.compatibleFeatures:
+ self.report("Not checking for missing forward links because the db " + \
+ "has the sortedLinks feature")
+ return (missing_forward_links, error_count)
+
+ try:
+ obj_guid = obj['objectGUID'][0]
+ obj_guid_str = str(ndr_unpack(misc.GUID, obj_guid))
+ filter = "(%s=<GUID=%s>)" % (backlink_attr, obj_guid_str)
+
+ res = self.samdb.search(expression=filter,
+ scope=ldb.SCOPE_SUBTREE, attrs=["objectGUID"],
+ controls=["extended_dn:1:1",
+ "search_options:1:2",
+ "paged_results:1:1000"])
+ except ldb.LdbError, (enum, estr):
+ raise
+
+ for r in res:
+ target_dn = dsdb_Dn(self.samdb, r.dn.extended_str(), forward_syntax)
+
+ guid = target_dn.dn.get_extended_component("GUID")
+ guidstr = str(misc.GUID(guid))
+ if guidstr in forward_unique_dict:
+ continue
+
+ # A valid forward link looks like this:
+ #
+ # <GUID=9f92d30a-fc23-11e4-a5f6-30be15454808>;
+ # <RMD_ADDTIME=131607546230000000>;
+ # <RMD_CHANGETIME=131607546230000000>;
+ # <RMD_FLAGS=0>;
+ # <RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;
+ # <RMD_LOCAL_USN=3765>;
+ # <RMD_ORIGINATING_USN=3765>;
+ # <RMD_VERSION=1>;
+ # <SID=S-1-5-21-4177067393-1453636373-93818738-1124>;
+ # CN=unsorted-u8,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ #
+ # Note that versions older than Samba 4.8 create
+ # links with RMD_VERSION=0.
+ #
+ # Try to get the local_usn and time from objectClass
+ # if possible and fallback to any other one.
+ repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
+ obj['replPropertyMetadata'][0])
+ for o in repl.ctr.array:
+ local_usn = o.local_usn
+ t = o.originating_change_time
+ if o.attid == drsuapi.DRSUAPI_ATTID_objectClass:
+ break
+
+ # We use a magic invocationID for restoring missing
+ # forward links to recover from bug #13228.
+ # This should allow some more future magic to fix the
+ # problem.
+ #
+ # It also means it looses the conflict resolution
+ # against almost every real invocation, if the
+ # version is also 0.
+ originating_invocid = misc.GUID("ffffffff-4700-4700-4700-000000b13228")
+ originating_usn = 1
+
+ rmd_addtime = t
+ rmd_changetime = t
+ rmd_flags = 0
+ rmd_invocid = originating_invocid
+ rmd_originating_usn = originating_usn
+ rmd_local_usn = local_usn
+ rmd_version = 0
+
+ target_dn.dn.set_extended_component("RMD_ADDTIME", str(rmd_addtime))
+ target_dn.dn.set_extended_component("RMD_CHANGETIME", str(rmd_changetime))
+ target_dn.dn.set_extended_component("RMD_FLAGS", str(rmd_flags))
+ target_dn.dn.set_extended_component("RMD_INVOCID", ndr_pack(rmd_invocid))
+ target_dn.dn.set_extended_component("RMD_ORIGINATING_USN", str(rmd_originating_usn))
+ target_dn.dn.set_extended_component("RMD_LOCAL_USN", str(rmd_local_usn))
+ target_dn.dn.set_extended_component("RMD_VERSION", str(rmd_version))
+
+ error_count += 1
+ missing_forward_links.append(target_dn)
+
+ return (missing_forward_links, error_count)
+
+ def check_dn(self, obj, attrname, syntax_oid):
+ '''check a DN attribute for correctness'''
+ error_count = 0
+ obj_guid = obj['objectGUID'][0]
+
+ linkID, reverse_link_name = self.get_attr_linkID_and_reverse_name(attrname)
+ if reverse_link_name is not None:
+ reverse_syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName(reverse_link_name)
+ else:
+ reverse_syntax_oid = None
+
+ error_count, duplicate_dict, unique_dict = \
+ self.check_duplicate_links(obj, attrname, syntax_oid, linkID, reverse_link_name)
+
+ if len(duplicate_dict) != 0:
+
+ missing_forward_links, missing_error_count = \
+ self.find_missing_forward_links_from_backlinks(obj,
+ attrname, syntax_oid,
+ reverse_link_name,
+ unique_dict)
+ error_count += missing_error_count
+
+ forward_links = [dn for dn in unique_dict.values()]
+
+ if missing_error_count != 0:
+ self.report("ERROR: Missing and duplicate forward link values for attribute '%s' in '%s'" % (
+ attrname, obj.dn))
+ else:
+ self.report("ERROR: Duplicate forward link values for attribute '%s' in '%s'" % (attrname, obj.dn))
+ for m in missing_forward_links:
+ self.report("Missing link '%s'" % (m))
+ if not self.confirm_all("Schedule readding missing forward link for attribute %s" % attrname,
+ 'fix_all_missing_forward_links'):
+ self.err_orphaned_backlink(m.dn, reverse_link_name,
+ obj.dn.extended_str(), obj.dn,
+ attrname, syntax_oid,
+ check_duplicates=False)
+ continue
+ forward_links += [m]
+ for keystr in duplicate_dict.keys():
d = duplicate_dict[keystr]
for dd in d["delete"]:
self.report("Duplicate link '%s'" % dd)
self.report("Correct link '%s'" % d["keep"])
- vals = []
- for keystr in unique_list:
- dsdb_dn = unique_dict[keystr]
- vals.append(str(dsdb_dn))
- self.err_duplicate_links(obj, attrname, vals)
+ # We now construct the sorted dn values.
+ # They're sorted by the objectGUID of the target
+ # See dsdb_Dn.__cmp__()
+ vals = [str(dn) for dn in sorted(forward_links)]
+ self.err_recover_forward_links(obj, attrname, vals)
# We should continue with the fixed values
- obj[attrname] = ldb.MessageElement(vals, ldb.FLAG_MOD_REPLACE, attrname)
+ obj[attrname] = ldb.MessageElement(vals, 0, attrname)
for val in obj[attrname]:
dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid)
@@ -1162,9 +1350,10 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
# UNLESS, there is no forward link detected.
if match_count == 0:
error_count += 1
- self.err_orphaned_backlink(obj, attrname,
- val, reverse_link_name,
- dsdb_dn.dn, duplicate_links)
+ self.err_orphaned_backlink(obj.dn, attrname,
+ val, dsdb_dn.dn,
+ reverse_link_name,
+ reverse_syntax_oid)
continue
# Only warn here and let the forward link logic fix it.
self.report("WARNING: Link (back) mismatch for '%s' (%d) on '%s' to '%s' (%d) on '%s'" % (
@@ -1194,9 +1383,9 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
dsdb_dn.dn)
diff_count -= 1
else:
- self.err_orphaned_backlink(res[0], reverse_link_name,
- obj.dn.extended_str(), attrname,
- obj.dn, duplicate_links)
+ self.err_orphaned_backlink(res[0].dn, reverse_link_name,
+ obj.dn.extended_str(), obj.dn,
+ attrname, syntax_oid)
diff_count += 1
@@ -1774,10 +1963,21 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
attrs.append(dn.get_rdn_name())
attrs.append("isDeleted")
attrs.append("systemFlags")
+ need_replPropertyMetaData = False
if '*' in attrs:
- attrs.append("replPropertyMetaData")
+ need_replPropertyMetaData = True
else:
- attrs.append("objectGUID")
+ for a in attrs:
+ linkID, _ = self.get_attr_linkID_and_reverse_name(a)
+ if linkID == 0:
+ continue
+ if linkID & 1:
+ continue
+ need_replPropertyMetaData = True
+ break
+ if need_replPropertyMetaData:
+ attrs.append("replPropertyMetaData")
+ attrs.append("objectGUID")
try:
sd_flags = 0
diff --git a/python/samba/netcmd/__init__.py b/python/samba/netcmd/__init__.py
index 05ecc43..fcad7f6 100644
--- a/python/samba/netcmd/__init__.py
+++ b/python/samba/netcmd/__init__.py
@@ -243,3 +243,6 @@ class CommandError(Exception):
self.message = message
self.inner_exception = inner_exception
self.exception_info = sys.exc_info()
+
+ def __repr__(self):
+ return "CommandError(%s)" % self.message
diff --git a/python/samba/tests/common.py b/python/samba/tests/common.py
index 8794e9d..49ae2b0 100644
--- a/python/samba/tests/common.py
+++ b/python/samba/tests/common.py
@@ -23,7 +23,7 @@ from samba.common import *
from samba.samdb import SamDB
-class CommonTests(samba.tests.TestCase):
+class CommonTests(samba.tests.TestCaseInTempDir):
def test_normalise_int32(self):
self.assertEquals('17', normalise_int32(17))
@@ -31,10 +31,35 @@ class CommonTests(samba.tests.TestCase):
self.assertEquals('-123', normalise_int32('-123'))
self.assertEquals('-1294967296', normalise_int32('3000000000'))
- def test_dsdb_Dn(self):
- sam = samba.Ldb(url='dntest.ldb')
+ def test_dsdb_Dn_binary(self):
+ url = self.tempdir + "/test_dsdb_Dn_binary.ldb"
+ sam = samba.Ldb(url=url)
dn1 = dsdb_Dn(sam, "DC=foo,DC=bar")
--
Samba Shared Repository
More information about the samba-cvs
mailing list