[SCM] Samba Shared Repository - branch master updated
Stefan Metzmacher
metze at samba.org
Fri Nov 24 18:54:02 UTC 2017
The branch, master has been updated
via 6cf7abb repl_meta_data: Allow delete of an object with dangling backlinks
via 40bd7e1 repl_meta_data: Fix removing of backlink on deleted objects
via 4815efc selftest: Add more corruption cases for runtime and dbcheck
via 70bf809 selftest: add dbcheck tests for duplicate links
via 239fbeb dbcheck: detect and fix duplicate links
via 9a63156 dbcheck: only calculate linked attribute helper variables once in check_dn()
via eb6bd65 dbcheck: remove indentation level
via 83aa222 dsdb:extended_dn_store: implement DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS control
via 9a1e23a dsdb:repl_meta_data: implement DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS control
via 1eb8d8e s4:dsdb: allocate DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS oid
via 126d28d s4:schema_samba4: mark DSDB_CONTROL_INVALID_NOT_IMPLEMENTED 1.3.6.1.4.1.7165.4.3.32 as allocated
via a784cc3 selftest: Additional check for a backlink pointing at a deleted object
via 25ae8d7 selftest: Split out creation of complex (often invalid) links
via b99d2ee selftest: Split out dbcheck runs from dangling_multi_valued test
via 7be38c6 selftest: add more dbcheck tests
via 527f2c9 dbcheck: Use the GUID as the DN to fix replPropertyMetaData
via 3b111fb dbcheck: Clarify error count bumping in deleted/gone DN handling
from f026314 ctdb-eventd: Simplify eventd code
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 6cf7abbcfdad84fee57852862ebe44aa6115ca25
Author: Andrew Bartlett <abartlet at samba.org>
Date: Wed Nov 1 08:22:22 2017 +1300
repl_meta_data: Allow delete of an object with dangling backlinks
This should not happen, but stopping all replication because of it is a pain.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
Autobuild-Date(master): Fri Nov 24 19:53:50 CET 2017 on sn-devel-144
commit 40bd7e145a68c9a58d6bc3c5526a12fdf0027729
Author: Andrej Gessel <Andrej.Gessel at janztec.com>
Date: Thu Oct 19 17:16:37 2017 +0200
repl_meta_data: Fix removing of backlink on deleted objects
USER is memberOf GROUP and they both were deleted on W2K8R2 AD. Domain join ends
with error below.
Failed to apply records: ../source4/dsdb/samdb/ldb_modules/repl_meta_data.c:421
8: Failed to remove backlink of memberOf when deleting CN=USER\0ADEL:a1f2a2cc-1
179-4734-b753-c121ed02a34c,CN=Deleted Objects,DC=samdom,DC=intern: dsdb_module_
search_dn: did not find base dn CN=GROUP\0ADEL:030d0be1-3ada-4b93-8371-927f2092
3116,CN=Deleted Objects,DC=samdom,DC=intern (0 results): Operations error
Failed to commit objects: WERR_GEN_FAILURE/NT_STATUS_INVALID_NETWORK_RESPONSE
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13120
Signed-off-by: Andrej Gessel <Andrej.Gessel at janztec.com>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 4815efc0e3f89079e7c9b868b7514ea7c49a807c
Author: Andrew Bartlett <abartlet at samba.org>
Date: Wed Nov 1 09:02:01 2017 +1300
selftest: Add more corruption cases for runtime and dbcheck
These tests now confirm we can handle these issues at runtime
as well as at dbcheck
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 70bf809e0cdf84029022ca95fb83d17a0d6e36c0
Author: Stefan Metzmacher <metze at samba.org>
Date: Thu Oct 26 14:42:23 2017 +0200
selftest: add dbcheck tests for duplicate links
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Pair-Programmed-With: Andrew Bartlett <abartlet at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
commit 239fbeb163c24b0f08e1bd9d8f7a9f73443d4b90
Author: Stefan Metzmacher <metze at samba.org>
Date: Fri Oct 27 10:21:26 2017 +0200
dbcheck: detect and fix duplicate links
Check with git show -w
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 9a631560c9358e4f28b96fecf23a545e1d04098c
Author: Stefan Metzmacher <metze at samba.org>
Date: Fri Oct 27 10:21:26 2017 +0200
dbcheck: only calculate linked attribute helper variables once in check_dn()
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit eb6bd6511a98dafebaa0d3951fe78c77acf13e3a
Author: Stefan Metzmacher <metze at samba.org>
Date: Thu Oct 26 16:30:28 2017 +0200
dbcheck: remove indentation level
Check with git show -w
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 83aa22260bd39ad0e6aab7764f9a7fc915d02a4b
Author: Stefan Metzmacher <metze at samba.org>
Date: Thu Oct 26 07:47:48 2017 +0200
dsdb:extended_dn_store: implement DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS control
This will be used by dbcheck to fix duplicate link values.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 9a1e23a1f67c38248e41e0d3aa2af8a682477364
Author: Stefan Metzmacher <metze at samba.org>
Date: Wed Oct 25 16:48:44 2017 +0200
dsdb:repl_meta_data: implement DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS control
This will be used by dbcheck to fix duplicate link values.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 1eb8d8ec5a62baf1b8e3c7cb1856787de4a3ccb2
Author: Stefan Metzmacher <metze at samba.org>
Date: Wed Oct 25 16:47:36 2017 +0200
s4:dsdb: allocate DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS oid
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 126d28d0b58740a8abd4137562dda685a57449bb
Author: Stefan Metzmacher <metze at samba.org>
Date: Wed Oct 25 16:26:16 2017 +0200
s4:schema_samba4: mark DSDB_CONTROL_INVALID_NOT_IMPLEMENTED 1.3.6.1.4.1.7165.4.3.32 as allocated
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit a784cc3a7f2043a5762d426e904a90e44b101ecd
Author: Andrew Bartlett <abartlet at samba.org>
Date: Tue Oct 31 11:20:34 2017 +1300
selftest: Additional check for a backlink pointing at a deleted object
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 25ae8d72d66cbe7342b50254ede7e5890bc23b73
Author: Andrew Bartlett <abartlet at samba.org>
Date: Tue Oct 31 08:23:39 2017 +1300
selftest: Split out creation of complex (often invalid) links
This will allow us to test other run-time behaviour with broken
databases.
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit b99d2ee122991d0bf1742fa5665656bbbba44057
Author: Andrew Bartlett <abartlet at samba.org>
Date: Tue Oct 31 08:21:15 2017 +1300
selftest: Split out dbcheck runs from dangling_multi_valued test
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 7be38c605468786894a373e15068b8017323da78
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Oct 30 15:29:36 2017 +1300
selftest: add more dbcheck tests
This validates some more combinations and ensures that the changes
in 962a1b32201fce0a49c6be55943d4fbb57ed781e are tested.
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 527f2c95cfe24d29fa34ed19db3b073781d96d9a
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Oct 30 10:51:35 2017 +1300
dbcheck: Use the GUID as the DN to fix replPropertyMetaData
This allows this to still work after an object is renamed under the deleted objects container.
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 3b111fbdbed99d5d90c1120243200baae9867534
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Oct 30 09:48:43 2017 +1300
dbcheck: Clarify error count bumping in deleted/gone DN handling
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
-----------------------------------------------------------------------
Summary of changes:
python/samba/dbchecker.py | 287 +++++++++++++++------
selftest/knownfail | 2 +-
selftest/tests.py | 5 +
source4/dsdb/samdb/ldb_modules/extended_dn_store.c | 7 +
source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 81 +++++-
source4/dsdb/samdb/samdb.h | 3 +
.../add-dangling-deleted-link.ldif | 5 +
.../add-deleted-backlink-user.ldif | 3 +
...ing-backlink.ldif => add-deleted-backlink.ldif} | 3 +-
.../add-deleted-target-backlink-user.ldif | 3 +
.../add-deleted-target-backlink.ldif | 4 +
...-one-way-link.ldif => dangling-one-way-dn.ldif} | 0
.../release-4-5-0-pre1/dangling-one-way-link.ldif | 22 +-
.../release-4-5-0-pre1/deleted-one-way-dn.ldif | 13 +
.../expected-dbcheck-link-output.txt | 58 +++--
...pected-dbcheck-link-output_duplicate_member.txt | 8 +
.../expected-dbcheck-link-output_one_way.txt | 7 +
.../expected-duplicates-after-link-dbcheck.ldif | 28 ++
.../revive-backlink-on-deleted-group.ldif | 5 +
.../revive-links-on-deleted-group.ldif | 20 ++
source4/setup/schema_samba4.ldif | 2 +
testprogs/blackbox/common-links.sh | 215 +++++++++++++++
testprogs/blackbox/dbcheck-links.sh | 210 +++++----------
testprogs/blackbox/runtime-links.sh | 74 ++++++
24 files changed, 792 insertions(+), 273 deletions(-)
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/add-dangling-deleted-link.ldif
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink-user.ldif
copy source4/selftest/provisions/release-4-5-0-pre1/{add-dangling-backlink.ldif => add-deleted-backlink.ldif} (67%)
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink-user.ldif
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink.ldif
copy source4/selftest/provisions/release-4-5-0-pre1/{dangling-one-way-link.ldif => dangling-one-way-dn.ldif} (100%)
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/deleted-one-way-dn.ldif
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_duplicate_member.txt
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_one_way.txt
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/expected-duplicates-after-link-dbcheck.ldif
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/revive-backlink-on-deleted-group.ldif
create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/revive-links-on-deleted-group.ldif
create mode 100644 testprogs/blackbox/common-links.sh
create mode 100755 testprogs/blackbox/runtime-links.sh
Changeset truncated at 500 lines:
diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 82088a0..1933740 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -65,6 +65,7 @@ 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_rmd_flags = False
self.fix_ntsecuritydescriptor = False
self.fix_ntsecuritydescriptor_owner_group = False
@@ -498,13 +499,15 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
def err_deleted_dn(self, dn, attrname, val, dsdb_dn, correct_dn, remove_plausible=False):
"""handle a DN pointing to a deleted object"""
- self.report("ERROR: target DN is deleted for %s in object %s - %s" % (attrname, dn, val))
- self.report("Target GUID points at deleted DN %r" % str(correct_dn))
if not remove_plausible:
+ self.report("ERROR: target DN is deleted for %s in object %s - %s" % (attrname, dn, val))
+ self.report("Target GUID points at deleted DN %r" % str(correct_dn))
if not self.confirm_all('Remove DN link?', 'remove_implausible_deleted_DN_links'):
self.report("Not removing")
return
else:
+ self.report("WARNING: target DN is deleted for %s in object %s - %s" % (attrname, dn, val))
+ self.report("Target GUID points at deleted DN %r" % str(correct_dn))
if not self.confirm_all('Remove stale DN link?', 'remove_plausible_deleted_DN_links'):
self.report("Not removing")
return
@@ -527,23 +530,45 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
linkID, reverse_link_name \
= self.get_attr_linkID_and_reverse_name(attrname)
if reverse_link_name is not None:
+ self.report("WARNING: no target object found for GUID "
+ "component for one-way forward link "
+ "%s in object "
+ "%s - %s" % (attrname, dn, val))
self.report("Not removing dangling forward link")
- return
+ return 0
nc_root = self.samdb.get_nc_root(dn)
target_nc_root = self.samdb.get_nc_root(dsdb_dn.dn)
if nc_root != target_nc_root:
+ # We don't bump the error count as Samba produces these
+ # in normal operation
+ self.report("WARNING: no target object found for GUID "
+ "component for cross-partition link "
+ "%s in object "
+ "%s - %s" % (attrname, dn, val))
self.report("Not removing dangling one-way "
"cross-partition link "
"(we might be mid-replication)")
- return
+ return 0
# Due to our link handling one-way links pointing to
# missing objects are plausible.
+ #
+ # We don't bump the error count as Samba produces these
+ # in normal operation
+ self.report("WARNING: no target object found for GUID "
+ "component for DN value %s in object "
+ "%s - %s" % (attrname, dn, val))
self.err_deleted_dn(dn, attrname, val,
dsdb_dn, dsdb_dn, True)
+ return 0
+ # We bump the error count here, as we should have deleted this
+ self.report("ERROR: no target object found for GUID "
+ "component for link %s in object "
+ "%s - %s" % (attrname, dn, val))
self.err_deleted_dn(dn, attrname, val, dsdb_dn, dsdb_dn, False)
+ return 1
def err_missing_dn_GUID_component(self, dn, attrname, val, dsdb_dn, errstr):
"""handle a missing GUID extended DN component"""
@@ -696,6 +721,19 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
"Failed to fix orphaned backlink %s" % attrname):
self.report("Fixed orphaned backlink %s" % (attrname))
+ def err_duplicate_links(self, obj, attrname, vals):
+ '''handle a duplicate links value'''
+
+ 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)
+ return
+ m = ldb.Message()
+ m.dn = obj.dn
+ m['value'] = ldb.MessageElement(vals, ldb.FLAG_MOD_REPLACE, attrname)
+ 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))
+
def err_no_fsmoRoleOwner(self, obj):
'''handle a missing fSMORoleOwner'''
self.report("ERROR: fSMORoleOwner not found for role %s" % (obj.dn))
@@ -852,6 +890,81 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
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_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)
+
+ # all DNs should have a GUID component
+ guid = dsdb_dn.dn.get_extended_component("GUID")
+ if guid is None:
+ continue
+ guidstr = str(misc.GUID(guid))
+ 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"))
+ v2 = int(dsdb_dn.dn.get_extended_component("RMD_VERSION"))
+ if v1 > v2:
+ duplicate_dict[keystr]["keep"] = unique_dict[keystr]
+ duplicate_dict[keystr]["delete"].append(dsdb_dn)
+ continue
+ if v1 < v2:
+ duplicate_dict[keystr]["keep"] = dsdb_dn
+ duplicate_dict[keystr]["delete"].append(unique_dict[keystr])
+ unique_dict[keystr] = dsdb_dn
+ continue
+ # Fallback to the highest RMD_LOCAL_USN
+ u1 = int(unique_dict[keystr].dn.get_extended_component("RMD_LOCAL_USN"))
+ u2 = int(dsdb_dn.dn.get_extended_component("RMD_LOCAL_USN"))
+ if u1 >= u2:
+ duplicate_dict[keystr]["keep"] = unique_dict[keystr]
+ duplicate_dict[keystr]["delete"].append(dsdb_dn)
+ continue
+ duplicate_dict[keystr]["keep"] = dsdb_dn
+ duplicate_dict[keystr]["delete"].append(unique_dict[keystr])
+ unique_dict[keystr] = dsdb_dn
+
+ if len(duplicate_list) != 0:
+ self.report("ERROR: Duplicate link values for attribute '%s' in '%s'" % (attrname, obj.dn))
+ for keystr in duplicate_list:
+ 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 should continue with the fixed values
+ obj[attrname] = ldb.MessageElement(vals, ldb.FLAG_MOD_REPLACE, attrname)
+
for val in obj[attrname]:
dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid)
@@ -872,7 +985,6 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
else:
fixing_msDS_HasInstantiatedNCs = False
- linkID, reverse_link_name = self.get_attr_linkID_and_reverse_name(attrname)
if reverse_link_name is not None:
attrs.append(reverse_link_name)
@@ -883,12 +995,14 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
"reveal_internals:0"
])
except ldb.LdbError, (enum, estr):
- error_count += 1
- self.report("ERROR: no target object found for GUID component for %s in object %s - %s" % (attrname, obj.dn, val))
if enum != ldb.ERR_NO_SUCH_OBJECT:
raise
- self.err_missing_target_dn_or_GUID(obj.dn, attrname, val, dsdb_dn)
+ # We don't always want to
+ error_count += self.err_missing_target_dn_or_GUID(obj.dn,
+ attrname,
+ val,
+ dsdb_dn)
continue
if fixing_msDS_HasInstantiatedNCs:
@@ -944,16 +1058,15 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
# components on deleted links, as these are allowed to
# go stale (we just need the GUID, not the name)
rmd_blob = dsdb_dn.dn.get_extended_component("RMD_FLAGS")
+ rmd_flags = 0
if rmd_blob is not None:
rmd_flags = int(rmd_blob)
- if rmd_flags & 1:
- continue
# assert the DN matches in string form, where a reverse
# link exists, otherwise (below) offer to fix it as a non-error.
# The string form is essentially only kept for forensics,
# as we always re-resolve by GUID in normal operations.
- if reverse_link_name is not None:
+ if not rmd_flags & 1 and reverse_link_name is not None:
if str(res[0].dn) != str(dsdb_dn.dn):
error_count += 1
self.err_dn_component_target_mismatch(obj.dn, attrname, val, dsdb_dn,
@@ -982,76 +1095,93 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
res[0].dn)
continue
- else:
- # check the reverse_link is correct if there should be one
- match_count = 0
- if reverse_link_name in res[0]:
- for v in res[0][reverse_link_name]:
- v_guid = dsdb_Dn(self.samdb, v).dn.get_extended_component("GUID")
- if v_guid == obj_guid:
- match_count += 1
- if match_count != 1:
- reverse_syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName(reverse_link_name)
- if syntax_oid == dsdb.DSDB_SYNTAX_BINARY_DN or reverse_syntax_oid == dsdb.DSDB_SYNTAX_BINARY_DN:
- if not linkID & 1:
- # Forward binary multi-valued linked attribute
- forward_count = 0
- for w in obj[attrname]:
- w_guid = dsdb_Dn(self.samdb, w).dn.get_extended_component("GUID")
- if w_guid == guid:
- forward_count += 1
-
- if match_count == forward_count:
- continue
-
- error_count += 1
-
- # Add or remove the missing number of backlinks
- diff_count = forward_count - match_count
-
- # Loop until the difference between the forward and
- # the backward links is resolved.
- while diff_count != 0:
- if diff_count > 0:
- # self.err_missing_backlink(obj, attrname,
- # obj.dn.extended_str(),
- # reverse_link_name,
- # dsdb_dn.dn)
- # diff_count -= 1
- # TODO no method to fix these right now
- self.report("ERROR: Can't fix missing "
- "multi-valued backlinks on %s" % str(dsdb_dn.dn))
- break
- else:
- self.err_orphaned_backlink(res[0], reverse_link_name,
- obj.dn.extended_str(), attrname,
- dsdb_dn.dn)
- diff_count += 1
+ # check the reverse_link is correct if there should be one
+ match_count = 0
+ if reverse_link_name in res[0]:
+ for v in res[0][reverse_link_name]:
+ v_dn = dsdb_Dn(self.samdb, v)
+ v_guid = v_dn.dn.get_extended_component("GUID")
+ v_blob = v_dn.dn.get_extended_component("RMD_FLAGS")
+ v_rmd_flags = 0
+ if v_blob is not None:
+ v_rmd_flags = int(v_blob)
+ if v_rmd_flags & 1:
+ continue
+ if v_guid == obj_guid:
+ match_count += 1
+
+ if match_count != 1:
+ if syntax_oid == dsdb.DSDB_SYNTAX_BINARY_DN or reverse_syntax_oid == dsdb.DSDB_SYNTAX_BINARY_DN:
+ if not linkID & 1:
+ # Forward binary multi-valued linked attribute
+ forward_count = 0
+ for w in obj[attrname]:
+ w_guid = dsdb_Dn(self.samdb, w).dn.get_extended_component("GUID")
+ if w_guid == guid:
+ forward_count += 1
+
+ if match_count == forward_count:
+ continue
+ expected_count = 0
+ for v in obj[attrname]:
+ v_dn = dsdb_Dn(self.samdb, v)
+ v_guid = v_dn.dn.get_extended_component("GUID")
+ v_blob = v_dn.dn.get_extended_component("RMD_FLAGS")
+ v_rmd_flags = 0
+ if v_blob is not None:
+ v_rmd_flags = int(v_blob)
+ if v_rmd_flags & 1:
+ continue
+ if v_guid == guid:
+ expected_count += 1
- else:
- # If there's a backward link on binary multi-valued linked attribute,
- # let the check on the forward link remedy the value.
- # UNLESS, there is no forward link detected.
- if match_count == 0:
- self.err_orphaned_backlink(obj, attrname,
- val, reverse_link_name,
- dsdb_dn.dn)
+ if match_count == expected_count:
+ continue
- continue
+ diff_count = expected_count - match_count
+ if linkID & 1:
+ # If there's a backward link on binary multi-valued linked attribute,
+ # let the check on the forward link remedy the value.
+ # UNLESS, there is no forward link detected.
+ if match_count == 0:
error_count += 1
- if linkID & 1:
- # Backlink exists, but forward link does not
- # Delete the hanging backlink
- self.err_orphaned_backlink(obj, attrname, val, reverse_link_name, dsdb_dn.dn)
- else:
- # Forward link exists, but backlink does not
- # Add the missing backlink (if the target object is not Deleted Objects?)
- if not target_is_deleted:
- self.err_missing_backlink(obj, attrname, obj.dn.extended_str(), reverse_link_name, dsdb_dn.dn)
+ self.err_orphaned_backlink(obj, attrname,
+ val, reverse_link_name,
+ dsdb_dn.dn)
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'" % (
+ attrname, expected_count, str(obj.dn),
+ reverse_link_name, match_count, str(dsdb_dn.dn)))
+ continue
+
+ assert not target_is_deleted
+ self.report("ERROR: Link (forward) mismatch for '%s' (%d) on '%s' to '%s' (%d) on '%s'" % (
+ attrname, expected_count, str(obj.dn),
+ reverse_link_name, match_count, str(dsdb_dn.dn)))
+ # Loop until the difference between the forward and
+ # the backward links is resolved.
+ while diff_count != 0:
+ error_count += 1
+ if diff_count > 0:
+ if match_count > 0 or diff_count > 1:
+ # TODO no method to fix these right now
+ self.report("ERROR: Can't fix missing "
+ "multi-valued backlinks on %s" % str(dsdb_dn.dn))
+ break
+ self.err_missing_backlink(obj, attrname,
+ obj.dn.extended_str(),
+ reverse_link_name,
+ dsdb_dn.dn)
+ diff_count -= 1
+ else:
+ self.err_orphaned_backlink(res[0], reverse_link_name,
+ obj.dn.extended_str(), attrname,
+ obj.dn)
+ diff_count += 1
return error_count
@@ -1097,11 +1227,14 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
return (set_att, list_attid, wrong_attids)
- def fix_metadata(self, dn, attr):
+ def fix_metadata(self, obj, attr):
'''re-write replPropertyMetaData elements for a single attribute for a
object. This is used to fix missing replPropertyMetaData elements'''
+ guid_str = str(ndr_unpack(misc.GUID, obj['objectGUID'][0]))
+ dn = ldb.Dn(self.samdb, "<GUID=%s>" % guid_str)
res = self.samdb.search(base = dn, scope=ldb.SCOPE_BASE, attrs = [attr],
- controls = ["search_options:1:2", "show_recycled:1"])
+ controls = ["search_options:1:2",
+ "show_recycled:1"])
msg = res[0]
nmsg = ldb.Message()
nmsg.dn = dn
@@ -1943,7 +2076,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
if not self.confirm_all("Fix missing replPropertyMetaData element '%s'" % att, 'fix_all_metadata'):
self.report("Not fixing missing replPropertyMetaData element '%s'" % att)
continue
- self.fix_metadata(dn, att)
+ self.fix_metadata(obj, att)
if self.is_fsmo_role(dn):
if "fSMORoleOwner" not in obj and ("*" in attrs or "fsmoroleowner" in map(str.lower, attrs)):
diff --git a/selftest/knownfail b/selftest/knownfail
index 3c910fb..a28329c 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -328,7 +328,7 @@
^samba3.smb2.credits.session_setup_credits_granted.*
^samba3.smb2.credits.single_req_credits_granted.*
^samba3.smb2.credits.skipped_mid.*
-^samba4.blackbox.dbcheck-links.release-4-5-0-pre1.dangling_multi_valued_dbcheck
+^samba4.blackbox.dbcheck-links.release-4-5-0-pre1.dbcheck_dangling_multi_valued_clean
^samba4.blackbox.dbcheck-links.release-4-5-0-pre1.dangling_multi_valued_check_missing
#
# rap password tests don't function in the ad_dc_ntvfs:local environment
diff --git a/selftest/tests.py b/selftest/tests.py
index 181313e..209800c 100644
--- a/selftest/tests.py
+++ b/selftest/tests.py
@@ -125,6 +125,11 @@ plantestsuite(
["PYTHON=%s" % python,
os.path.join(bbdir, "dbcheck-links.sh"),
'$PREFIX_ABS/provision', 'release-4-5-0-pre1', configuration])
+plantestsuite(
+ "samba4.blackbox.runtime-links.release-4-5-0-pre1", "none",
+ ["PYTHON=%s" % python,
+ os.path.join(bbdir, "runtime-links.sh"),
+ '$PREFIX_ABS/provision', 'release-4-5-0-pre1', configuration])
planpythontestsuite("none", "samba.tests.upgradeprovision")
planpythontestsuite("none", "samba.tests.xattr", py3_compatible=True)
planpythontestsuite("none", "samba.tests.ntacls")
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_store.c b/source4/dsdb/samdb/ldb_modules/extended_dn_store.c
index 28ad9d0..a32ab8d 100644
--- a/source4/dsdb/samdb/ldb_modules/extended_dn_store.c
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn_store.c
@@ -375,6 +375,7 @@ static int extended_dn_modify(struct ldb_module *module, struct ldb_request *req
unsigned int i, j;
struct extended_dn_context *ac;
+ struct ldb_control *fix_links_control = NULL;
int ret;
if (ldb_dn_is_special(req->op.mod.message->dn)) {
@@ -393,6 +394,12 @@ static int extended_dn_modify(struct ldb_module *module, struct ldb_request *req
return ldb_next_request(module, req);
}
+ fix_links_control = ldb_request_get_control(req,
+ DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS);
+ if (fix_links_control != NULL) {
+ return ldb_next_request(module, req);
+ }
+
for (i=0; i < req->op.mod.message->num_elements; i++) {
const struct ldb_message_element *el = &req->op.mod.message->elements[i];
const struct dsdb_attribute *schema_attr
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 9a24349..198ac84 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -3172,9 +3172,22 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
continue;
}
if ((schema_attr->linkID & 1) == 1) {
- if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
- continue;
+ if (parent) {
+ struct ldb_control *ctrl;
+
+ ctrl = ldb_request_get_control(parent,
+ DSDB_CONTROL_REPLMD_VANISH_LINKS);
+ if (ctrl != NULL) {
+ ctrl->critical = false;
+ continue;
+ }
+ ctrl = ldb_request_get_control(parent,
+ DSDB_CONTROL_DBCHECK);
+ if (ctrl != NULL) {
+ continue;
+ }
}
+
/* Odd is for the target. Illegal to modify */
ldb_asprintf_errstring(ldb,
"attribute %s must not be modified directly, it is a linked attribute", el->name);
@@ -3303,6 +3316,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
unsigned int functional_level;
const struct ldb_message_element *guid_el = NULL;
struct ldb_control *sd_propagation_control;
+ struct ldb_control *fix_links_control = NULL;
struct replmd_private *replmd_private =
talloc_get_type(ldb_module_get_private(module), struct replmd_private);
@@ -3328,6 +3342,39 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
--
Samba Shared Repository
More information about the samba-cvs
mailing list