[PATCH] run-time and dbcheck time wrong backlink handling

Andrew Bartlett abartlet at samba.org
Thu Nov 23 22:48:04 UTC 2017


On Thu, 2017-11-23 at 15:44 +0100, Stefan Metzmacher wrote:
> Hi Andrew,
> 
> > > > I'll try to combine it with my dbcheck patches to fix
> > > > the consequences of https://bugzilla.samba.org/show_bug.cgi?id=13095
> > > > 
> > > > See
> > > > https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/
> > > > v4-6-duplicate-links
> > > > and
> > > > https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/
> > > > v4-7-duplicate-links
> > > 
> > > I've tried to forward-port that to master, which was a mission, but I
> > > think I've done it.  More importantly I've improved the tests, and
> > > found it handles one issue I couldn't get the old dbcheck to find,
> > > which is a backlink to a deleted object.
> > > 
> > > The tests have been changed to use administrator and enterprise admins
> > > to keep stable GUIDs, and now reliably pass.
> > > 
> > > There is still more work to do to squash this in to a for-master patch
> > > series, and I may have totally mucked up the rebase, so please look
> > > carefully.
> > > 
> > > I wouldn't normally get into your WIP tree, but it seemed more helpful
> > > than continuing parallel development.
> > > 
> > > Thanks for all your work here, and I hope this is useful!
> > > 
> > > http://git.catalyst.net.nz/gitweb?p=samba.git;a=shortlog;h=refs/heads/abartlet-dbcheck-links-2017-11
> > 
> > G'Day,
> > 
> > I've updated that branch, and now have patches covering runtime as well
> > as dbcheck-time behaviour.  In particular, I can now cope with deleting
> > objects that had backlinks that we can assert are faulty (object
> > tomebstoned or missing).
> > 
> > I was hoping to get these fixes in to 4.7.1 but I think I'm too late
> > for that, but if you can help get these in to master that would be
> > great.  I've tried un-tangling it again from your code but that just
> > looks like being more difficult all-round.
> > 
> > If you could take a look at what I've done and finish tidying up your
> > patches that would be great.  If you could fix the existing failure in
> > dbcheck-links.dbcheck_dangling_multi_valued_clean that would be even
> > better!
> > 
> > The output is below, hidden normally because it is in knownfail.
> 
> Thanks! I cleaned up my patches and squashed a few things.
> 
> See
> https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/master4-duplicate-links
> 
> I left the last 4 unsquashed for further review from you.
> 
> We also need some more BUG: lines here and there.
> 
> https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/v4-7-duplicate-links
> contains backports
> 
> I'm currently running private autobuilds with both branches.

Thanks.  I've squashed it, added the sign-off from Andrej and reviewed
it.  It is in an autobuild here as well. 

I've also looked over the diff compared with the branch I had
previously, and the changes make sense. 

I think this is ready to go, so can you or I push it?

http://git.catalyst.net.nz/gitweb?p=samba.git;a=shortlog;h=refs/heads/metze-master4-duplicate-links

Thanks,

Andrew Bartlett
-- 
Andrew Bartlett
https://samba.org/~abartlet/
Authentication Developer, Samba Team         https://samba.org
Samba Development and Support, Catalyst IT   
https://catalyst.net.nz/services/samba



-------------- next part --------------
From e4a03a25cdeff68d8e40e7d6980735e9f324c61f Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 30 Oct 2017 09:48:43 +1300
Subject: [PATCH 01/17] 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>
---
 python/samba/dbchecker.py                          | 40 ++++++++++++++++++----
 .../expected-dbcheck-link-output.txt               | 34 +++++++++---------
 2 files changed, 50 insertions(+), 24 deletions(-)

diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 82088a00d14..8bbd65f4aae 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -498,13 +498,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 +529,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"""
@@ -883,12 +907,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:
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
index ea2ef233802..772331b3641 100644
--- a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
+++ b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
@@ -1,8 +1,11 @@
 Checking 223 objects
-ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: missing backlink attribute 'memberOf' in CN=dangling-forward,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Fix missing backlink memberOf [YES]
+Fixed missing backlink memberOf
+ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3728>;<RMD_ORIGINATING_USN=3728>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3728>;<RMD_ORIGINATING_USN=3728>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
@@ -11,38 +14,35 @@ Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: missing backlink attribute 'memberOf' in CN=dangling-forward,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-Fix missing backlink memberOf [YES]
-Fixed missing backlink memberOf
-ERROR: target DN is deleted for member in object CN=swimmers,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=2301a64c-5b42-4ca8-851e-12d4a711cfb4>;<RMD_ADDTIME=131116485990000000>;<RMD_CHANGETIME=131116485990000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3745>;<RMD_ORIGINATING_USN=3745>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1111>;CN=fred,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-Target GUID points at deleted DN 'CN=fred\\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
-Remove stale DN link? [YES]
-Removed deleted DN on attribute member
-ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3732>;<RMD_ORIGINATING_USN=3732>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3730>;<RMD_ORIGINATING_USN=3730>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=usg\0ADEL:d012e8f5-a4bd-40ea-a2a1-68ff2508847d,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3732>;<RMD_ORIGINATING_USN=3732>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3730>;<RMD_ORIGINATING_USN=3730>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=usg\0ADEL:d012e8f5-a4bd-40ea-a2a1-68ff2508847d,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3728>;<RMD_ORIGINATING_USN=3728>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3731>;<RMD_ORIGINATING_USN=3731>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=ddg\0ADEL:fb8c2fe3-5448-43de-99f9-e1d3b9357cfc,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3728>;<RMD_ORIGINATING_USN=3728>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3731>;<RMD_ORIGINATING_USN=3731>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=ddg\0ADEL:fb8c2fe3-5448-43de-99f9-e1d3b9357cfc,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
 ERROR: orphaned backlink attribute 'memberOf' in CN=dangling-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove orphaned backlink memberOf [YES]
 Fixed orphaned backlink memberOf
-ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3730>;<RMD_ORIGINATING_USN=3730>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=usg\0ADEL:d012e8f5-a4bd-40ea-a2a1-68ff2508847d,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+WARNING: target DN is deleted for member in object CN=swimmers,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=2301a64c-5b42-4ca8-851e-12d4a711cfb4>;<RMD_ADDTIME=131116485990000000>;<RMD_CHANGETIME=131116485990000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3745>;<RMD_ORIGINATING_USN=3745>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1111>;CN=fred,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Target GUID points at deleted DN 'CN=fred\\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Remove stale DN link? [YES]
+Removed deleted DN on attribute member
+ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3730>;<RMD_ORIGINATING_USN=3730>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=usg\0ADEL:d012e8f5-a4bd-40ea-a2a1-68ff2508847d,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3731>;<RMD_ORIGINATING_USN=3731>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=ddg\0ADEL:fb8c2fe3-5448-43de-99f9-e1d3b9357cfc,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3732>;<RMD_ORIGINATING_USN=3732>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3731>;<RMD_ORIGINATING_USN=3731>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=ddg\0ADEL:fb8c2fe3-5448-43de-99f9-e1d3b9357cfc,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3732>;<RMD_ORIGINATING_USN=3732>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
 Checked 223 objects (15 errors)
-- 
2.11.0


From 73d676e4726113173381720a4e3fbc43fd4651a6 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 30 Oct 2017 10:51:35 +1300
Subject: [PATCH 02/17] 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>
---
 python/samba/dbchecker.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 8bbd65f4aae..45bfdbf7479 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -1123,11 +1123,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
@@ -1969,7 +1972,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)):
-- 
2.11.0


From 4fcaf4d4b860700e1ba374312d7578b64652c9d1 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 30 Oct 2017 15:29:36 +1300
Subject: [PATCH 03/17] 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>
---
 .../add-dangling-deleted-link.ldif                 |  5 ++
 .../add-deleted-backlink-user.ldif                 |  3 +
 .../release-4-5-0-pre1/add-deleted-backlink.ldif   |  5 ++
 .../add-deleted-target-backlink-user.ldif          |  3 +
 .../add-deleted-target-backlink.ldif               |  4 +
 .../release-4-5-0-pre1/dangling-one-way-dn.ldif    | 15 ++++
 .../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               | 21 +++--
 .../expected-dbcheck-link-output_one_way.txt       |  7 ++
 testprogs/blackbox/dbcheck-links.sh                | 93 +++++++++++++++++++---
 11 files changed, 159 insertions(+), 32 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
 create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink.ldif
 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
 create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-dn.ldif
 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_one_way.txt

diff --git a/source4/selftest/provisions/release-4-5-0-pre1/add-dangling-deleted-link.ldif b/source4/selftest/provisions/release-4-5-0-pre1/add-dangling-deleted-link.ldif
new file mode 100644
index 00000000000..b740252e277
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/add-dangling-deleted-link.ldif
@@ -0,0 +1,5 @@
+dn: CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modify
+add: member
+member: <GUID=2301a64c-5b42-4ca8-851e-12d4a711cfb4>;<SID=S-1-5-21-4177067393-1453636373-93818738-1111>;CN=fred\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+-
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink-user.ldif b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink-user.ldif
new file mode 100644
index 00000000000..19b6d6525fa
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink-user.ldif
@@ -0,0 +1,3 @@
+dn: CN=deleted-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+objectclass: user
+samaccountname: deleted-back
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink.ldif b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink.ldif
new file mode 100644
index 00000000000..14e014ad2a6
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-backlink.ldif
@@ -0,0 +1,5 @@
+dn:CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modify
+add: memberOf
+memberOf: <GUID=a5b834bf-e4ca-4e1b-9c9f-0f01c9656f3b>;<SID=S-1-5-21-4177067393-1453636373-93818738-571>;CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+-
\ No newline at end of file
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink-user.ldif b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink-user.ldif
new file mode 100644
index 00000000000..6e99aae7375
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink-user.ldif
@@ -0,0 +1,3 @@
+dn: CN=deleted-target-back,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+objectclass: user
+samaccountname: deleted-target-back
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink.ldif b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink.ldif
new file mode 100644
index 00000000000..6a46e2827ee
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-target-backlink.ldif
@@ -0,0 +1,4 @@
+dn: CN=deleted-target-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modify
+add: memberOf
+memberOf: <GUID=e0f581e7-14ee-4fc2-839c-8f46f581c72a>;<SID=S-1-5-21-4177067393-1453636373-93818738-1109>;CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-dn.ldif b/source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-dn.ldif
new file mode 100644
index 00000000000..c215c0655c3
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-dn.ldif
@@ -0,0 +1,15 @@
+dn: CN=secretary,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: add
+objectclass: user
+samaccountname: secretary
+
+dn: CN=dangling-one-way,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: add
+objectclass: user
+samaccountname: dangling-one-way
+secretary: CN=secretary,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+
+dn: CN=secretary,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modrdn
+newrdn: cn=new-secretary
+deleteoldrdn: 1
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-link.ldif b/source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-link.ldif
index c215c0655c3..2e43cca6a17 100644
--- a/source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-link.ldif
+++ b/source4/selftest/provisions/release-4-5-0-pre1/dangling-one-way-link.ldif
@@ -1,15 +1,7 @@
-dn: CN=secretary,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-changetype: add
-objectclass: user
-samaccountname: secretary
-
-dn: CN=dangling-one-way,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-changetype: add
-objectclass: user
-samaccountname: dangling-one-way
-secretary: CN=secretary,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-
-dn: CN=secretary,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-changetype: modrdn
-newrdn: cn=new-secretary
-deleteoldrdn: 1
+dn: CN=36a28334-a8d3-4e67-bfe9-7e66c1af7cff,CN=Partitions,CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modify
+add: msDS-NC-Replica-Locations
+msDS-NC-Replica-Locations: <GUID=d2cadb04-6df2-4b99-b388-9fe2511767c4>;CN=NTDS
+  Settings,CN=NOT-A_SERVER,CN=Servers,CN=Default-First-Site-Name,CN=Sites,C
+ N=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp
+-
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/deleted-one-way-dn.ldif b/source4/selftest/provisions/release-4-5-0-pre1/deleted-one-way-dn.ldif
new file mode 100644
index 00000000000..b6cd3df02ce
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/deleted-one-way-dn.ldif
@@ -0,0 +1,13 @@
+dn: CN=secretary-del,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: add
+objectclass: user
+samaccountname: secretary-del
+
+dn: CN=deleted-one-way-del,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: add
+objectclass: user
+samaccountname: dangling-one-way-del
+secretary: CN=secretary-del,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+
+dn: CN=secretary-del,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: delete
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
index 772331b3641..44e10d01db9 100644
--- a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
+++ b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
@@ -1,13 +1,20 @@
-Checking 223 objects
+Checking 225 objects
 ERROR: missing backlink attribute 'memberOf' in CN=dangling-forward,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Fix missing backlink memberOf [YES]
 Fixed missing backlink memberOf
+ERROR: target DN is deleted for member in object CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=2301a64c-5b42-4ca8-851e-12d4a711cfb4>;<SID=S-1-5-21-4177067393-1453636373-93818738-1111>;CN=fred\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Target GUID points at deleted DN 'CN=fred\\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Remove DN link? [YES]
+Removed deleted DN on attribute member
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3728>;<RMD_ORIGINATING_USN=3728>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3728>;<RMD_ORIGINATING_USN=3728>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
+ERROR: linked attribute 'memberOf' to '<GUID=a5b834bf-e4ca-4e1b-9c9f-0f01c9656f3b>;<SID=S-1-5-21-4177067393-1453636373-93818738-571>;CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Remove linked attribute memberOf [YES]
+Fixed undead forward link memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
@@ -26,23 +33,27 @@ Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3731>;<RMD_ORIGINATING_USN=3731>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=ddg\0ADEL:fb8c2fe3-5448-43de-99f9-e1d3b9357cfc,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: orphaned backlink attribute 'memberOf' in CN=dangling-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-Remove orphaned backlink memberOf [YES]
-Fixed orphaned backlink memberOf
 WARNING: target DN is deleted for member in object CN=swimmers,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=2301a64c-5b42-4ca8-851e-12d4a711cfb4>;<RMD_ADDTIME=131116485990000000>;<RMD_CHANGETIME=131116485990000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3745>;<RMD_ORIGINATING_USN=3745>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1111>;CN=fred,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Target GUID points at deleted DN 'CN=fred\\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
 Remove stale DN link? [YES]
 Removed deleted DN on attribute member
+ERROR: target DN is deleted for memberOf in object CN=deleted-target-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=e0f581e7-14ee-4fc2-839c-8f46f581c72a>;<SID=S-1-5-21-4177067393-1453636373-93818738-1109>;CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Target GUID points at deleted DN 'CN=gdg\\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Remove DN link? [YES]
+Removed deleted DN on attribute memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
+ERROR: orphaned backlink attribute 'memberOf' in CN=dangling-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Remove orphaned backlink memberOf [YES]
+Fixed orphaned backlink memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3732>;<RMD_ORIGINATING_USN=3732>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3732>;<RMD_ORIGINATING_USN=3732>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-Checked 223 objects (15 errors)
+Checked 225 objects (18 errors)
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_one_way.txt b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_one_way.txt
new file mode 100644
index 00000000000..4309d1f7de7
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_one_way.txt
@@ -0,0 +1,7 @@
+Checking 1612 objects
+WARNING: no target object found for GUID component for DN value msDS-NC-Replica-Locations in object CN=36a28334-a8d3-4e67-bfe9-7e66c1af7cff,CN=Partitions,CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=d2cadb04-6df2-4b99-b388-9fe2511767c4>;CN=NTDS Settings,CN=NOT-A_SERVER,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp
+WARNING: target DN is deleted for msDS-NC-Replica-Locations in object CN=36a28334-a8d3-4e67-bfe9-7e66c1af7cff,CN=Partitions,CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=d2cadb04-6df2-4b99-b388-9fe2511767c4>;CN=NTDS Settings,CN=NOT-A_SERVER,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Target GUID points at deleted DN '<GUID=d2cadb04-6df2-4b99-b388-9fe2511767c4>;CN=NTDS Settings,CN=NOT-A_SERVER,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Remove stale DN link? [YES]
+Removed deleted DN on attribute msDS-NC-Replica-Locations
+Checked 1612 objects (0 errors)
diff --git a/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh
index 17973e97429..655e1aa2de0 100755
--- a/testprogs/blackbox/dbcheck-links.sh
+++ b/testprogs/blackbox/dbcheck-links.sh
@@ -50,31 +50,41 @@ undump() {
 }
 
 dbcheck() {
-    tmpfile=$PREFIX_ABS/$RELEASE/expected-dbcheck-link-output.txt.tmp
-    tmpldif1=$PREFIX_ABS/$RELEASE/expected-dbcheck-output2.txt.tmp1
+    tmpfile=$PREFIX_ABS/$RELEASE/expected-dbcheck-link-output${1}.txt.tmp
+    tmpldif1=$PREFIX_ABS/$RELEASE/expected-dbcheck-output${1}2.txt.tmp1
 
     TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb -s base -b '' | grep highestCommittedUSN > $tmpldif1
 
-    $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --fix --yes > $tmpfile
-    if [ "$?" != "1" ]; then
+    $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $3 --fix --yes > $tmpfile
+    if [ "$?" != "$2" ]; then
 	return 1
     fi
     sort $tmpfile > $tmpfile.sorted
-    sort $release_dir/expected-dbcheck-link-output.txt > $tmpfile.expected
+    sort $release_dir/expected-dbcheck-link-output${1}.txt > $tmpfile.expected
     diff -u $tmpfile.sorted $tmpfile.expected
     if [ "$?" != "0" ]; then
 	return 1
     fi
 
-    tmpldif2=$PREFIX_ABS/$RELEASE/expected-dbcheck-output2.txt.tmp2
+    tmpldif2=$PREFIX_ABS/$RELEASE/expected-dbcheck-output${1}2.txt.tmp2
     TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb -s base -b '' | grep highestCommittedUSN > $tmpldif2
 
-    diff $tmpldif1 $tmpldif2
+    diff -u $tmpldif1 $tmpldif2
     if [ "$?" != "0" ]; then
 	return 1
     fi
 }
 
+dbcheck_dangling() {
+    dbcheck "" "1" ""
+    return $?
+}
+
+dbcheck_one_way() {
+    dbcheck "_one_way" "0" "CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp"
+    return $?
+}
+
 dbcheck_clean() {
     tmpldif1=$PREFIX_ABS/$RELEASE/expected-dbcheck-output2.txt.tmp1
 
@@ -127,6 +137,42 @@ add_dangling_backlink() {
     fi
 }
 
+add_deleted_dangling_backlink() {
+    ldif=$release_dir/add-deleted-backlink-user.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-deleted-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_deleted_target_backlink() {
+    ldif=$release_dir/add-deleted-target-backlink-user.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-deleted-target-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_deleted_target_link() {
+    ldif=$release_dir/add-dangling-deleted-link.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
 add_two_more_users() {
     ldif=$release_dir/add-two-more-users.ldif
     TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
@@ -193,14 +239,30 @@ check_expected_after_objects() {
     fi
 }
 
-dangling_one_way() {
-    ldif=$release_dir/dangling-one-way-link.ldif
+dangling_one_way_dn() {
+    ldif=$release_dir/dangling-one-way-dn.ldif
     TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
     if [ "$?" != "0" ]; then
         return 1
     fi
 }
 
+deleted_one_way_dn() {
+    ldif=$release_dir/deleted-one-way-dn.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+        return 1
+    fi
+}
+
+dangling_one_way_link() {
+    ldif=$release_dir/dangling-one-way-link.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/CN%3DCONFIGURATION,DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+        return 1
+    fi
+}
+
 dangling_multi_valued() {
     # multi1 - All 4 backlinks
     # multi2 - Missing all 4 backlinks
@@ -282,13 +344,20 @@ if [ -d $release_dir ]; then
     testit "move_one_user" move_one_user
     testit "add_dangling_link" add_dangling_link
     testit "add_dangling_backlink" add_dangling_backlink
-    testit "dbcheck" dbcheck
+    testit "add_deleted_dangling_backlink" add_deleted_dangling_backlink
+    testit "add_deleted_target_link" add_deleted_target_link
+    testit "add_deleted_target_backlink" add_deleted_target_backlink
+    testit "dbcheck_dangling" dbcheck_dangling
     testit "dbcheck_clean" dbcheck_clean
     testit "check_expected_after_deleted_links" check_expected_after_deleted_links
     testit "check_expected_after_links" check_expected_after_links
     testit "check_expected_after_objects" check_expected_after_objects
-    testit "dangling_one_way" dangling_one_way
-    testit "dbcheck_clean" dbcheck_clean
+    testit "dangling_one_way_link" dangling_one_way_link
+    testit "dbcheck_one_way" dbcheck_one_way
+    testit "dbcheck_clean2" dbcheck_clean
+    testit "dangling_one_way_dn" dangling_one_way_dn
+    testit "deleted_one_way_dn" deleted_one_way_dn
+    testit "dbcheck_clean3" dbcheck_clean
     testit "dangling_multi_valued" dangling_multi_valued
     testit "dangling_multi_valued_check_missing" dangling_multi_valued_check_missing
     testit "dangling_multi_valued_check_equal_or_too_many" dangling_multi_valued_check_equal_or_too_many
-- 
2.11.0


From 710e0ef721d86cdd679b25a9c79aa84e202037ab Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 31 Oct 2017 08:21:15 +1300
Subject: [PATCH 04/17] 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>
---
 selftest/knownfail                  |  2 +-
 testprogs/blackbox/dbcheck-links.sh | 10 +++++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 3c910fb3d6f..a28329cd449 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/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh
index 655e1aa2de0..208ec00dfc0 100755
--- a/testprogs/blackbox/dbcheck-links.sh
+++ b/testprogs/blackbox/dbcheck-links.sh
@@ -263,7 +263,7 @@ dangling_one_way_link() {
     fi
 }
 
-dangling_multi_valued() {
+add_dangling_multi_valued() {
     # multi1 - All 4 backlinks
     # multi2 - Missing all 4 backlinks
     # multi3 - Missing 2 backlinks
@@ -292,6 +292,9 @@ dangling_multi_valued() {
     if [ "$?" != "0" ]; then
 	return 1
     fi
+}
+
+dbcheck_dangling_multi_valued() {
 
     $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --fix --yes
     if [ "$?" != "1" ]; then
@@ -358,11 +361,12 @@ if [ -d $release_dir ]; then
     testit "dangling_one_way_dn" dangling_one_way_dn
     testit "deleted_one_way_dn" deleted_one_way_dn
     testit "dbcheck_clean3" dbcheck_clean
-    testit "dangling_multi_valued" dangling_multi_valued
+    testit "add_dangling_multi_valued" add_dangling_multi_valued
+    testit "dbcheck_dangling_multi_valued" dbcheck_dangling_multi_valued
     testit "dangling_multi_valued_check_missing" dangling_multi_valued_check_missing
     testit "dangling_multi_valued_check_equal_or_too_many" dangling_multi_valued_check_equal_or_too_many
     # Currently this cannot pass
-    testit "dangling_multi_valued_dbcheck" dbcheck_clean
+    testit "dbcheck_dangling_multi_valued_clean" dbcheck_clean
 else
     subunit_start_test $RELEASE
     subunit_skip_test $RELEASE <<EOF
-- 
2.11.0


From 36c49913899ae96587692c7332049f1a1ec541fb Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 31 Oct 2017 08:23:39 +1300
Subject: [PATCH 05/17] 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>
---
 testprogs/blackbox/common-links.sh  | 199 +++++++++++++++++++++++++++++++++++
 testprogs/blackbox/dbcheck-links.sh | 200 +-----------------------------------
 2 files changed, 200 insertions(+), 199 deletions(-)
 create mode 100644 testprogs/blackbox/common-links.sh

diff --git a/testprogs/blackbox/common-links.sh b/testprogs/blackbox/common-links.sh
new file mode 100644
index 00000000000..7c80e35007a
--- /dev/null
+++ b/testprogs/blackbox/common-links.sh
@@ -0,0 +1,199 @@
+release_dir=`dirname $0`/../../source4/selftest/provisions/$RELEASE
+
+ldbadd="ldbadd"
+if [ -x "$BINDIR/ldbadd" ]; then
+    ldbadd="$BINDIR/ldbadd"
+fi
+
+ldbmodify="ldbmodify"
+if [ -x "$BINDIR/ldbmodify" ]; then
+    ldbmodify="$BINDIR/ldbmodify"
+fi
+
+ldbdel="ldbdel"
+if [ -x "$BINDIR/ldbdel" ]; then
+    ldbdel="$BINDIR/ldbdel"
+fi
+
+ldbsearch="ldbsearch"
+if [ -x "$BINDIR/ldbsearch" ]; then
+    ldbsearch="$BINDIR/ldbsearch"
+fi
+
+ldbrename="ldbrename"
+if [ -x "$BINDIR/ldbrename" ]; then
+    ldbrename="$BINDIR/ldbrename"
+fi
+
+undump() {
+       if test -x $BINDIR/tdbrestore;
+       then
+	`dirname $0`/../../source4/selftest/provisions/undump.sh $release_dir $PREFIX_ABS/$RELEASE $BINDIR/tdbrestore
+       else
+	`dirname $0`/../../source4/selftest/provisions/undump.sh $release_dir $PREFIX_ABS/$RELEASE
+       fi
+}
+
+add_dangling_link() {
+    ldif=$release_dir/add-dangling-forwardlink-user.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-initially-normal-link.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/delete-only-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_dangling_backlink() {
+    ldif=$release_dir/add-dangling-backlink-user.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-dangling-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_deleted_dangling_backlink() {
+    ldif=$release_dir/add-deleted-backlink-user.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-deleted-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_deleted_target_backlink() {
+    ldif=$release_dir/add-deleted-target-backlink-user.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-deleted-target-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_deleted_target_link() {
+    ldif=$release_dir/add-dangling-deleted-link.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_two_more_users() {
+    ldif=$release_dir/add-two-more-users.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+add_four_more_links() {
+    ldif=$release_dir/add-four-more-links.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+remove_one_link() {
+    ldif=$release_dir/remove-one-more-link.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+remove_one_user() {
+    ldif=$release_dir/remove-one-more-user.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+move_one_user() {
+    TZ=UTC $ldbrename -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb 'cn=user1,cn=users,DC=release-4-5-0-pre1,DC=samba,DC=corp' 'cn=user1x,cn=users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+dangling_one_way_dn() {
+    ldif=$release_dir/dangling-one-way-dn.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+        return 1
+    fi
+}
+
+deleted_one_way_dn() {
+    ldif=$release_dir/deleted-one-way-dn.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+        return 1
+    fi
+}
+
+dangling_one_way_link() {
+    ldif=$release_dir/dangling-one-way-link.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/CN%3DCONFIGURATION,DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+        return 1
+    fi
+}
+
+add_dangling_multi_valued() {
+    # multi1 - All 4 backlinks
+    # multi2 - Missing all 4 backlinks
+    # multi3 - Missing 2 backlinks
+    # Administrator - Has 2 too many backlinks
+    # multi5 - Has 2 backlinks but no forward links
+    ldif=$release_dir/add-dangling-multilink-users.ldif
+    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-initially-normal-multilink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/delete-only-multi-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+
+    ldif=$release_dir/add-dangling-multi-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
diff --git a/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh
index 208ec00dfc0..e1db50f4faa 100755
--- a/testprogs/blackbox/dbcheck-links.sh
+++ b/testprogs/blackbox/dbcheck-links.sh
@@ -13,41 +13,7 @@ shift 2
 
 . `dirname $0`/subunit.sh
 
-release_dir=`dirname $0`/../../source4/selftest/provisions/$RELEASE
-
-ldbadd="ldbadd"
-if [ -x "$BINDIR/ldbadd" ]; then
-    ldbadd="$BINDIR/ldbadd"
-fi
-
-ldbmodify="ldbmodify"
-if [ -x "$BINDIR/ldbmodify" ]; then
-    ldbmodify="$BINDIR/ldbmodify"
-fi
-
-ldbdel="ldbdel"
-if [ -x "$BINDIR/ldbdel" ]; then
-    ldbdel="$BINDIR/ldbdel"
-fi
-
-ldbsearch="ldbsearch"
-if [ -x "$BINDIR/ldbsearch" ]; then
-    ldbsearch="$BINDIR/ldbsearch"
-fi
-
-ldbrename="ldbrename"
-if [ -x "$BINDIR/ldbrename" ]; then
-    ldbrename="$BINDIR/ldbrename"
-fi
-
-undump() {
-       if test -x $BINDIR/tdbrestore;
-       then
-	`dirname $0`/../../source4/selftest/provisions/undump.sh $release_dir $PREFIX_ABS/$RELEASE $BINDIR/tdbrestore
-       else
-	`dirname $0`/../../source4/selftest/provisions/undump.sh $release_dir $PREFIX_ABS/$RELEASE
-       fi
-}
+. `dirname $0`/common-links.sh
 
 dbcheck() {
     tmpfile=$PREFIX_ABS/$RELEASE/expected-dbcheck-link-output${1}.txt.tmp
@@ -103,115 +69,6 @@ dbcheck_clean() {
     fi
 }
 
-add_dangling_link() {
-    ldif=$release_dir/add-dangling-forwardlink-user.ldif
-    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/add-initially-normal-link.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/delete-only-backlink.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-add_dangling_backlink() {
-    ldif=$release_dir/add-dangling-backlink-user.ldif
-    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/add-dangling-backlink.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-add_deleted_dangling_backlink() {
-    ldif=$release_dir/add-deleted-backlink-user.ldif
-    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/add-deleted-backlink.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-add_deleted_target_backlink() {
-    ldif=$release_dir/add-deleted-target-backlink-user.ldif
-    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/add-deleted-target-backlink.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-add_deleted_target_link() {
-    ldif=$release_dir/add-dangling-deleted-link.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-add_two_more_users() {
-    ldif=$release_dir/add-two-more-users.ldif
-    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-add_four_more_links() {
-    ldif=$release_dir/add-four-more-links.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-remove_one_link() {
-    ldif=$release_dir/remove-one-more-link.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-remove_one_user() {
-    ldif=$release_dir/remove-one-more-user.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
-move_one_user() {
-    TZ=UTC $ldbrename -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb 'cn=user1,cn=users,DC=release-4-5-0-pre1,DC=samba,DC=corp' 'cn=user1x,cn=users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
 check_expected_after_links() {
     tmpldif=$PREFIX_ABS/$RELEASE/expected-links-after-link-dbcheck.ldif.tmp
     TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb '(|(cn=swimmers)(cn=leaders)(cn=helpers))' -s sub -b DC=release-4-5-0-pre1,DC=samba,DC=corp --show-deleted --sorted member > $tmpldif
@@ -239,61 +96,6 @@ check_expected_after_objects() {
     fi
 }
 
-dangling_one_way_dn() {
-    ldif=$release_dir/dangling-one-way-dn.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-        return 1
-    fi
-}
-
-deleted_one_way_dn() {
-    ldif=$release_dir/deleted-one-way-dn.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-        return 1
-    fi
-}
-
-dangling_one_way_link() {
-    ldif=$release_dir/dangling-one-way-link.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/CN%3DCONFIGURATION,DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-        return 1
-    fi
-}
-
-add_dangling_multi_valued() {
-    # multi1 - All 4 backlinks
-    # multi2 - Missing all 4 backlinks
-    # multi3 - Missing 2 backlinks
-    # Administrator - Has 2 too many backlinks
-    # multi5 - Has 2 backlinks but no forward links
-    ldif=$release_dir/add-dangling-multilink-users.ldif
-    TZ=UTC $ldbadd -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/add-initially-normal-multilink.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/delete-only-multi-backlink.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-
-    ldif=$release_dir/add-dangling-multi-backlink.ldif
-    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
-    if [ "$?" != "0" ]; then
-	return 1
-    fi
-}
-
 dbcheck_dangling_multi_valued() {
 
     $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --fix --yes
-- 
2.11.0


From e80c76ffd0fff744bc797a68b5181f754138e3b3 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 31 Oct 2017 11:20:34 +1300
Subject: [PATCH 06/17] 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>
---
 .../release-4-5-0-pre1/add-deleted-source-backlink.ldif           | 6 ++++++
 testprogs/blackbox/common-links.sh                                | 8 ++++++++
 testprogs/blackbox/dbcheck-links.sh                               | 1 +
 3 files changed, 15 insertions(+)
 create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/add-deleted-source-backlink.ldif

diff --git a/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-source-backlink.ldif b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-source-backlink.ldif
new file mode 100644
index 00000000000..40e2f8cddff
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-source-backlink.ldif
@@ -0,0 +1,6 @@
+dn: CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modify
+add: memberOf
+memberOf: <GUID=7cff5537-51b1-4d26-a295-0225dbea8525>;<SID=S-1-5-21-4177067393-1453636373-93818738-1110>;CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+-
+# in group udg, the link is deleted, so this is sort of a dangling backlink too
\ No newline at end of file
diff --git a/testprogs/blackbox/common-links.sh b/testprogs/blackbox/common-links.sh
index 7c80e35007a..e36cb0b8f66 100644
--- a/testprogs/blackbox/common-links.sh
+++ b/testprogs/blackbox/common-links.sh
@@ -96,6 +96,14 @@ add_deleted_target_backlink() {
     fi
 }
 
+add_deleted_source_backlink() {
+    ldif=$release_dir/add-deleted-source-backlink.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
 add_deleted_target_link() {
     ldif=$release_dir/add-dangling-deleted-link.ldif
     TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
diff --git a/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh
index e1db50f4faa..a64e8a326d6 100755
--- a/testprogs/blackbox/dbcheck-links.sh
+++ b/testprogs/blackbox/dbcheck-links.sh
@@ -150,6 +150,7 @@ if [ -d $release_dir ]; then
     testit "add_dangling_link" add_dangling_link
     testit "add_dangling_backlink" add_dangling_backlink
     testit "add_deleted_dangling_backlink" add_deleted_dangling_backlink
+    testit "add_deleted_source_backlink" add_deleted_source_backlink
     testit "add_deleted_target_link" add_deleted_target_link
     testit "add_deleted_target_backlink" add_deleted_target_backlink
     testit "dbcheck_dangling" dbcheck_dangling
-- 
2.11.0


From 2307c550b5f2a88beb927d955c43da10e95c45a3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 25 Oct 2017 16:26:16 +0200
Subject: [PATCH 07/17] 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>
---
 source4/setup/schema_samba4.ldif | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif
index 4fd729e3149..8525f6ab496 100644
--- a/source4/setup/schema_samba4.ldif
+++ b/source4/setup/schema_samba4.ldif
@@ -224,6 +224,7 @@
 #Allocated: DSDB_CONTROL_REPLMD_VANISH_LINKS 1.3.6.1.4.1.7165.4.3.29
 #Allocated: LDB_CONTROL_RECALCULATE_RDN_OID 1.3.6.1.4.1.7165.4.3.30
 #Allocated: DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE 1.3.6.1.4.1.7165.4.3.31
+#Allocated: DSDB_CONTROL_INVALID_NOT_IMPLEMENTED 1.3.6.1.4.1.7165.4.3.32
 
 
 # Extended 1.3.6.1.4.1.7165.4.4.x
-- 
2.11.0


From 6b36a05fb51d17b3e90c319f046e27f4186ce3bf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 25 Oct 2017 16:47:36 +0200
Subject: [PATCH 08/17] 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>
---
 source4/dsdb/samdb/samdb.h       | 3 +++
 source4/setup/schema_samba4.ldif | 1 +
 2 files changed, 4 insertions(+)

diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h
index 01eb1f3c087..617edc9aa2b 100644
--- a/source4/dsdb/samdb/samdb.h
+++ b/source4/dsdb/samdb/samdb.h
@@ -127,6 +127,9 @@ struct dsdb_control_password_change {
 /* passed when dbcheck wants to modify a read only replica (very special case) */
 #define DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA "1.3.6.1.4.1.7165.4.3.19.1"
 
+/* passed by dbcheck to fix duplicate linked attributes (bug #13095) */
+#define DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS "1.3.6.1.4.1.7165.4.3.19.2"
+
 /* passed when importing plain text password on upgrades */
 #define DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID "1.3.6.1.4.1.7165.4.3.20"
 
diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif
index 8525f6ab496..ebc1ae6df6b 100644
--- a/source4/setup/schema_samba4.ldif
+++ b/source4/setup/schema_samba4.ldif
@@ -213,6 +213,7 @@
 #Allocated: DSDB_CONTROL_PARTIAL_REPLICA 1.3.6.1.4.1.7165.4.3.18
 #Allocated: DSDB_CONTROL_DBCHECK 1.3.6.1.4.1.7165.4.3.19
 #Allocated: DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA 1.3.6.1.4.1.7165.4.3.19.1
+#Allocated: DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS 1.3.6.1.4.1.7165.4.3.19.2
 #Allocated: DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID 1.3.6.1.4.1.7165.4.3.20
 #Allocated: DSDB_CONTROL_SEC_DESC_PROPAGATION_OID 1.3.6.1.4.1.7165.4.3.21
 #Allocated: DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID 1.3.6.1.4.1.7165.4.3.23
-- 
2.11.0


From 06911efe9f6fb390bb2df9fcfe97e6e6b24fecd9 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 25 Oct 2017 16:48:44 +0200
Subject: [PATCH 09/17] 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>
---
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 34 +++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 9a243497be7..c7aacd83615 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -3303,6 +3303,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 +3329,39 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
 
 	ldb = ldb_module_get_ctx(module);
 
+	fix_links_control = ldb_request_get_control(req,
+					DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS);
+	if (fix_links_control != NULL) {
+		struct dsdb_schema *schema = NULL;
+		const struct dsdb_attribute *sa = NULL;
+
+		if (req->op.mod.message->num_elements != 1) {
+			return ldb_module_operr(module);
+		}
+
+		if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_REPLACE) {
+			return ldb_module_operr(module);
+		}
+
+		schema = dsdb_get_schema(ldb, req);
+		if (schema == NULL) {
+			return ldb_module_operr(module);
+		}
+
+		sa = dsdb_attribute_by_lDAPDisplayName(schema,
+				req->op.mod.message->elements[0].name);
+		if (sa == NULL) {
+			return ldb_module_operr(module);
+		}
+
+		if (sa->linkID == 0) {
+			return ldb_module_operr(module);
+		}
+
+		fix_links_control->critical = false;
+		return ldb_next_request(module, req);
+	}
+
 	ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
 
 	guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
-- 
2.11.0


From 339403fdb5384ad1c323547e659378f73340476f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 26 Oct 2017 07:47:48 +0200
Subject: [PATCH 10/17] 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>
---
 source4/dsdb/samdb/ldb_modules/extended_dn_store.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_store.c b/source4/dsdb/samdb/ldb_modules/extended_dn_store.c
index 28ad9d01a8b..a32ab8d6f93 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
-- 
2.11.0


From 70f1fff76eaaf548b5c830120a4ec0d8ab58da65 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 26 Oct 2017 16:30:28 +0200
Subject: [PATCH 11/17] 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>
---
 python/samba/dbchecker.py | 125 +++++++++++++++++++++++-----------------------
 1 file changed, 62 insertions(+), 63 deletions(-)

diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 45bfdbf7479..3ecb17aa4d3 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -1008,75 +1008,74 @@ 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_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
 
-                        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)
+                        error_count += 1
 
-                        continue
+                        # 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
 
-                    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)
+                        # 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)
+
                     continue
 
+                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)
+                continue
+
 
 
 
-- 
2.11.0


From 89c36597aed9819ce8e3a38bb7eac29a1c2c70db Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 27 Oct 2017 10:21:26 +0200
Subject: [PATCH 12/17] 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>
---
 python/samba/dbchecker.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 3ecb17aa4d3..dafa8443d24 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -876,6 +876,12 @@ 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
+
         for val in obj[attrname]:
             dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid)
 
@@ -896,7 +902,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)
 
@@ -1016,7 +1021,6 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                     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
-- 
2.11.0


From e3a286937084d1d0f38af60695a30de9b0a1fbb0 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 27 Oct 2017 10:21:26 +0200
Subject: [PATCH 13/17] 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>
---
 python/samba/dbchecker.py                          | 193 ++++++++++++++++-----
 .../expected-dbcheck-link-output.txt               |   9 +-
 2 files changed, 152 insertions(+), 50 deletions(-)

diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index dafa8443d24..193374041fe 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
@@ -720,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))
@@ -882,6 +896,75 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
         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)
 
@@ -975,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,
@@ -1017,9 +1099,17 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
             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")
+                    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:
@@ -1032,55 +1122,66 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
 
                         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
 
-                        error_count += 1
+            if match_count == expected_count:
+                continue
 
-                        # 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
-
-                    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)
+            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
+                    self.err_orphaned_backlink(obj, attrname,
+                                               val, reverse_link_name,
+                                               dsdb_dn.dn)
                     continue
-
-                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)
+                # 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
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
index 44e10d01db9..6f0d2fc2bd6 100644
--- a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
+++ b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
@@ -1,4 +1,5 @@
 Checking 225 objects
+ERROR: Link (forward) mismatch for 'member' (1) on 'CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' to 'memberOf' (0) on 'CN=dangling-forward,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
 ERROR: missing backlink attribute 'memberOf' in CN=dangling-forward,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Fix missing backlink memberOf [YES]
 Fixed missing backlink memberOf
@@ -27,6 +28,10 @@ Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3730>;<RMD_ORIGINATING_USN=3730>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=usg\0ADEL:d012e8f5-a4bd-40ea-a2a1-68ff2508847d,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
+ERROR: target DN is deleted for memberOf in object CN=deleted-target-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=e0f581e7-14ee-4fc2-839c-8f46f581c72a>;<SID=S-1-5-21-4177067393-1453636373-93818738-1109>;CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Target GUID points at deleted DN 'CN=gdg\\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Remove DN link? [YES]
+Removed deleted DN on attribute memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3731>;<RMD_ORIGINATING_USN=3731>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=ddg\0ADEL:fb8c2fe3-5448-43de-99f9-e1d3b9357cfc,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
@@ -37,10 +42,6 @@ WARNING: target DN is deleted for member in object CN=swimmers,CN=Users,DC=relea
 Target GUID points at deleted DN 'CN=fred\\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
 Remove stale DN link? [YES]
 Removed deleted DN on attribute member
-ERROR: target DN is deleted for memberOf in object CN=deleted-target-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=e0f581e7-14ee-4fc2-839c-8f46f581c72a>;<SID=S-1-5-21-4177067393-1453636373-93818738-1109>;CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
-Target GUID points at deleted DN 'CN=gdg\\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
-Remove DN link? [YES]
-Removed deleted DN on attribute memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-- 
2.11.0


From 698fbe83163ca94c9d836e119732c3995b933cbf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 26 Oct 2017 14:42:23 +0200
Subject: [PATCH 14/17] selftest: add dbcheck tests for the 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>
---
 ...pected-dbcheck-link-output_duplicate_member.txt |  8 +++++
 .../expected-duplicates-after-link-dbcheck.ldif    | 28 ++++++++++++++++
 testprogs/blackbox/dbcheck-links.sh                | 39 ++++++++++++++++++++++
 3 files changed, 75 insertions(+)
 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-duplicates-after-link-dbcheck.ldif

diff --git a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_duplicate_member.txt b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_duplicate_member.txt
new file mode 100644
index 00000000000..baa11ca3fd6
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output_duplicate_member.txt
@@ -0,0 +1,8 @@
+Checking 225 objects
+WARNING: Link (back) mismatch for 'memberOf' (1) on 'CN=Administrator,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' to 'member' (2) on 'CN=Enterprise Admins,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+ERROR: Duplicate link values for attribute 'member' in 'CN=Enterprise Admins,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Duplicate link '<GUID=f4616422-30ec-473b-9d6f-a9a2d7bd1e6a>;<RMD_ADDTIME=131116484540000000>;<RMD_CHANGETIME=131116484540000000>;<RMD_FLAGS=0>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=0>;<RMD_ORIGINATING_USN=3552>;<RMD_VERSION=0>;<SID=S-1-5-21-4177067393-1453636373-93818738-500>;CN=Administrator,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Correct   link '<GUID=f4616422-30ec-473b-9d6f-a9a2d7bd1e6a>;<RMD_ADDTIME=131116484540000000>;<RMD_CHANGETIME=131116484540000000>;<RMD_FLAGS=0>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3552>;<RMD_ORIGINATING_USN=3552>;<RMD_VERSION=0>;<SID=S-1-5-21-4177067393-1453636373-93818738-500>;CN=Administrator,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Remove duplicate links in attribute 'member' [YES]
+Fixed duplicate links in attribute 'member'
+Checked 225 objects (1 errors)
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/expected-duplicates-after-link-dbcheck.ldif b/source4/selftest/provisions/release-4-5-0-pre1/expected-duplicates-after-link-dbcheck.ldif
new file mode 100644
index 00000000000..e70426c9b89
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/expected-duplicates-after-link-dbcheck.ldif
@@ -0,0 +1,28 @@
+# record 1
+dn: CN=Administrator,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+memberOf: CN=Administrators,CN=Builtin,DC=release-4-5-0-pre1,DC=samba,DC=corp
+memberOf: CN=Group Policy Creator Owners,CN=Users,DC=release-4-5-0-pre1,DC=sam
+ ba,DC=corp
+memberOf: CN=Enterprise Admins,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+memberOf: CN=Schema Admins,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+memberOf: CN=Domain Admins,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+
+# record 2
+dn: CN=Enterprise Admins,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+member: CN=Administrator,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+memberOf: CN=Administrators,CN=Builtin,DC=release-4-5-0-pre1,DC=samba,DC=corp
+memberOf: CN=Denied RODC Password Replication Group,CN=Users,DC=release-4-5-0-
+ pre1,DC=samba,DC=corp
+
+# Referral
+ref: ldap:///CN=Configuration,DC=release-4-5-0-pre1,DC=samba,DC=corp
+
+# Referral
+ref: ldap:///DC=DomainDnsZones,DC=release-4-5-0-pre1,DC=samba,DC=corp
+
+# Referral
+ref: ldap:///DC=ForestDnsZones,DC=release-4-5-0-pre1,DC=samba,DC=corp
+
+# returned 5 records
+# 2 entries
+# 3 referrals
diff --git a/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh
index a64e8a326d6..074b60164dd 100755
--- a/testprogs/blackbox/dbcheck-links.sh
+++ b/testprogs/blackbox/dbcheck-links.sh
@@ -96,6 +96,41 @@ check_expected_after_objects() {
     fi
 }
 
+duplicate_member() {
+    # We use an exisiting group so we have a stable GUID in the
+    # dbcheck output
+    LDIF1=$(TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb -b 'CN=Enterprise Admins,CN=users,DC=release-4-5-0-pre1,DC=samba,DC=corp' -s base --reveal --extended-dn member)
+    DN=$(echo "${LDIF1}" | grep '^dn: ')
+    MSG=$(echo "${LDIF1}" | grep -v '^dn: ' | grep -v '^#' | grep -v '^$')
+    ldif=$PREFIX_ABS/${RELEASE}/duplicate-member-multi.ldif
+    {
+	echo "${DN}"
+	echo "changetype: modify"
+	echo "replace: member"
+	echo "${MSG}"
+	echo "${MSG}" | sed -e 's!RMD_LOCAL_USN=[1-9][0-9]*!RMD_LOCAL_USN=0!'
+    } > $ldif
+
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+dbcheck_duplicate_member() {
+    dbcheck "_duplicate_member" "1" ""
+    return $?
+}
+
+check_expected_after_duplicate_links() {
+    tmpldif=$PREFIX_ABS/$RELEASE/expected-duplicates-after-link-dbcheck.ldif.tmp
+    TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb '(|(cn=administrator)(cn=enterprise admins))' -s sub -b DC=release-4-5-0-pre1,DC=samba,DC=corp --show-deleted --sorted memberOf member > $tmpldif
+    diff $tmpldif $release_dir/expected-duplicates-after-link-dbcheck.ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
 dbcheck_dangling_multi_valued() {
 
     $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --fix --yes
@@ -158,6 +193,10 @@ if [ -d $release_dir ]; then
     testit "check_expected_after_deleted_links" check_expected_after_deleted_links
     testit "check_expected_after_links" check_expected_after_links
     testit "check_expected_after_objects" check_expected_after_objects
+    testit "duplicate_member" duplicate_member
+    testit "dbcheck_duplicate_member" dbcheck_duplicate_member
+    testit "check_expected_after_duplicate_links" check_expected_after_duplicate_links
+    testit "duplicate_clean" dbcheck_clean
     testit "dangling_one_way_link" dangling_one_way_link
     testit "dbcheck_one_way" dbcheck_one_way
     testit "dbcheck_clean2" dbcheck_clean
-- 
2.11.0


From 3e99167e907779057899c2aa0eb1238c47d8aa74 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Nov 2017 09:02:01 +1300
Subject: [PATCH 15/17] 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>
---
 .../knownfail.d/delete_member_of_deleted_group     |  1 +
 selftest/knownfail.d/runtime-links                 |  2 +
 selftest/tests.py                                  |  5 ++
 .../expected-dbcheck-link-output.txt               | 16 ++---
 ....ldif => revive-backlink-on-deleted-group.ldif} |  3 +-
 .../revive-links-on-deleted-group.ldif             | 20 ++++++
 testprogs/blackbox/common-links.sh                 | 12 +++-
 testprogs/blackbox/dbcheck-links.sh                |  3 +-
 testprogs/blackbox/runtime-links.sh                | 74 ++++++++++++++++++++++
 9 files changed, 123 insertions(+), 13 deletions(-)
 create mode 100644 selftest/knownfail.d/delete_member_of_deleted_group
 create mode 100644 selftest/knownfail.d/runtime-links
 rename source4/selftest/provisions/release-4-5-0-pre1/{add-deleted-source-backlink.ldif => revive-backlink-on-deleted-group.ldif} (62%)
 create mode 100644 source4/selftest/provisions/release-4-5-0-pre1/revive-links-on-deleted-group.ldif
 create mode 100755 testprogs/blackbox/runtime-links.sh

diff --git a/selftest/knownfail.d/delete_member_of_deleted_group b/selftest/knownfail.d/delete_member_of_deleted_group
new file mode 100644
index 00000000000..f399d33ccc1
--- /dev/null
+++ b/selftest/knownfail.d/delete_member_of_deleted_group
@@ -0,0 +1 @@
+^samba4\.blackbox\.runtime-links\.release-4-5-0-pre1\.delete_member_of_deleted_group
\ No newline at end of file
diff --git a/selftest/knownfail.d/runtime-links b/selftest/knownfail.d/runtime-links
new file mode 100644
index 00000000000..70de8be3d55
--- /dev/null
+++ b/selftest/knownfail.d/runtime-links
@@ -0,0 +1,2 @@
+^samba4\.blackbox\.runtime-links\.release-4-5-0-pre1\.delete_backlink_memberof_deleted_group
+^samba4\.blackbox\.runtime-links\.release-4-5-0-pre1\.delete_dangling_backlink_memberof_group
\ No newline at end of file
diff --git a/selftest/tests.py b/selftest/tests.py
index 181313ebc95..209800c8ba4 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/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
index 6f0d2fc2bd6..5a083f7da79 100644
--- a/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
+++ b/source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output.txt
@@ -7,6 +7,9 @@ ERROR: target DN is deleted for member in object CN=Allowed RODC Password Replic
 Target GUID points at deleted DN 'CN=fred\\0ADEL:2301a64c-5b42-4ca8-851e-12d4a711cfb4,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
 Remove DN link? [YES]
 Removed deleted DN on attribute member
+ERROR: orphaned backlink attribute 'memberOf' in CN=dangling-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Remove orphaned backlink memberOf [YES]
+Fixed orphaned backlink memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3728>;<RMD_ORIGINATING_USN=3728>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=dsg\0ADEL:6d66d0ef-cad7-4e5d-b1b6-4a233a21c269,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
@@ -19,7 +22,7 @@ Fixed undead forward link memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=0>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3730>;<RMD_ORIGINATING_USN=3730>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=usg\0ADEL:d012e8f5-a4bd-40ea-a2a1-68ff2508847d,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
@@ -28,10 +31,6 @@ Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3730>;<RMD_ORIGINATING_USN=3730>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=usg\0ADEL:d012e8f5-a4bd-40ea-a2a1-68ff2508847d,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: target DN is deleted for memberOf in object CN=deleted-target-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=e0f581e7-14ee-4fc2-839c-8f46f581c72a>;<SID=S-1-5-21-4177067393-1453636373-93818738-1109>;CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
-Target GUID points at deleted DN 'CN=gdg\\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
-Remove DN link? [YES]
-Removed deleted DN on attribute memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484680000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3731>;<RMD_ORIGINATING_USN=3731>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=ddg\0ADEL:fb8c2fe3-5448-43de-99f9-e1d3b9357cfc,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
@@ -48,9 +47,10 @@ Fixed undead forward link member
 ERROR: linked attribute 'member' to '<GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=131116484670000000>;<RMD_CHANGETIME=131116484700000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3729>;<RMD_ORIGINATING_USN=3729>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gsg\0ADEL:91aa85cc-fc19-4b8c-9fc7-aaba425439c7,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
-ERROR: orphaned backlink attribute 'memberOf' in CN=dangling-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp for link member in CN=Allowed RODC Password Replication Group,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
-Remove orphaned backlink memberOf [YES]
-Fixed orphaned backlink memberOf
+ERROR: target DN is deleted for memberOf in object CN=deleted-target-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp - <GUID=e0f581e7-14ee-4fc2-839c-8f46f581c72a>;<SID=S-1-5-21-4177067393-1453636373-93818738-1109>;CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+Target GUID points at deleted DN 'CN=gdg\\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+Remove DN link? [YES]
+Removed deleted DN on attribute memberOf
 ERROR: linked attribute 'member' to '<GUID=118943ce-41c2-48cb-a511-b68c6feaa8aa>;<RMD_ADDTIME=131116484690000000>;<RMD_CHANGETIME=131116484710000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3732>;<RMD_ORIGINATING_USN=3732>;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1103>;CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp' is present on deleted object CN=gdg\0ADEL:e0f581e7-14ee-4fc2-839c-8f46f581c72a,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 Remove linked attribute member [YES]
 Fixed undead forward link member
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-source-backlink.ldif b/source4/selftest/provisions/release-4-5-0-pre1/revive-backlink-on-deleted-group.ldif
similarity index 62%
rename from source4/selftest/provisions/release-4-5-0-pre1/add-deleted-source-backlink.ldif
rename to source4/selftest/provisions/release-4-5-0-pre1/revive-backlink-on-deleted-group.ldif
index 40e2f8cddff..8bfcbb7b4a4 100644
--- a/source4/selftest/provisions/release-4-5-0-pre1/add-deleted-source-backlink.ldif
+++ b/source4/selftest/provisions/release-4-5-0-pre1/revive-backlink-on-deleted-group.ldif
@@ -1,6 +1,5 @@
-dn: CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+dn: CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
 changetype: modify
 add: memberOf
 memberOf: <GUID=7cff5537-51b1-4d26-a295-0225dbea8525>;<SID=S-1-5-21-4177067393-1453636373-93818738-1110>;CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
 -
-# in group udg, the link is deleted, so this is sort of a dangling backlink too
\ No newline at end of file
diff --git a/source4/selftest/provisions/release-4-5-0-pre1/revive-links-on-deleted-group.ldif b/source4/selftest/provisions/release-4-5-0-pre1/revive-links-on-deleted-group.ldif
new file mode 100644
index 00000000000..a4301a068f4
--- /dev/null
+++ b/source4/selftest/provisions/release-4-5-0-pre1/revive-links-on-deleted-group.ldif
@@ -0,0 +1,20 @@
+dn: CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modify
+add: memberOf
+memberOf: <GUID=7cff5537-51b1-4d26-a295-0225dbea8525>;<SID=S-1-5-21-4177067393-1453636373-93818738-1110>;CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+-
+
+dn: CN=udg\0ADEL:7cff5537-51b1-4d26-a295-0225dbea8525,CN=Deleted Objects,DC=release-4-5-0-pre1,DC=samba,DC=corp
+changetype: modify
+delete: member
+member: <GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=1311164846900
+ 00000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=1>;<RMD_INVOCID=4e4496a
+ 3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733
+ >;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1
+  UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
+add: member
+member: <GUID=50d78122-17c8-4352-acf0-8f549b5b5b3c>;<RMD_ADDTIME=1311164846900
+ 00000>;<RMD_CHANGETIME=131116484720000000>;<RMD_FLAGS=0>;<RMD_INVOCID=4e4496a
+ 3-7fb8-4f97-8a33-d238db8b5e2d>;<RMD_LOCAL_USN=3733>;<RMD_ORIGINATING_USN=3733
+ >;<RMD_VERSION=1>;<SID=S-1-5-21-4177067393-1453636373-93818738-1104>;CN=User1
+  UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp
\ No newline at end of file
diff --git a/testprogs/blackbox/common-links.sh b/testprogs/blackbox/common-links.sh
index e36cb0b8f66..ee7310b5108 100644
--- a/testprogs/blackbox/common-links.sh
+++ b/testprogs/blackbox/common-links.sh
@@ -96,8 +96,16 @@ add_deleted_target_backlink() {
     fi
 }
 
-add_deleted_source_backlink() {
-    ldif=$release_dir/add-deleted-source-backlink.ldif
+revive_links_on_deleted_group() {
+    ldif=$release_dir/revive-links-on-deleted-group.ldif
+    TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+revive_backlink_on_deleted_group() {
+    ldif=$release_dir/revive-backlink-on-deleted-group.ldif
     TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-5-0-PRE1,DC%3DSAMBA,DC%3DCORP.ldb $ldif
     if [ "$?" != "0" ]; then
 	return 1
diff --git a/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh
index 074b60164dd..0aeada037fc 100755
--- a/testprogs/blackbox/dbcheck-links.sh
+++ b/testprogs/blackbox/dbcheck-links.sh
@@ -185,7 +185,8 @@ if [ -d $release_dir ]; then
     testit "add_dangling_link" add_dangling_link
     testit "add_dangling_backlink" add_dangling_backlink
     testit "add_deleted_dangling_backlink" add_deleted_dangling_backlink
-    testit "add_deleted_source_backlink" add_deleted_source_backlink
+    testit "revive_links_on_deleted_group" revive_links_on_deleted_group
+    testit "revive_backlink_on_deleted_group" revive_backlink_on_deleted_group
     testit "add_deleted_target_link" add_deleted_target_link
     testit "add_deleted_target_backlink" add_deleted_target_backlink
     testit "dbcheck_dangling" dbcheck_dangling
diff --git a/testprogs/blackbox/runtime-links.sh b/testprogs/blackbox/runtime-links.sh
new file mode 100755
index 00000000000..344b822f07e
--- /dev/null
+++ b/testprogs/blackbox/runtime-links.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+cat <<EOF
+Usage: dbcheck-links.sh PREFIX RELEASE
+EOF
+exit 1;
+fi
+
+PREFIX_ABS="$1"
+RELEASE="$2"
+shift 2
+
+. `dirname $0`/subunit.sh
+
+. `dirname $0`/common-links.sh
+
+delete_member_of_deleted_group() {
+    TZ=UTC $ldbdel -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb 'CN=User1 UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+delete_backlink_memberof_deleted_group() {
+    TZ=UTC $ldbdel -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb 'CN=User UT. Tester,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+delete_dangling_backlink_memberof_group() {
+    TZ=UTC $ldbdel -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb 'CN=dangling-back,CN=Users,DC=release-4-5-0-pre1,DC=samba,DC=corp'
+    if [ "$?" != "0" ]; then
+	return 1
+    fi
+}
+
+
+if [ -d $release_dir ]; then
+    testit $RELEASE undump
+    testit "add_dangling_link" add_dangling_link
+    testit "add_dangling_backlink" add_dangling_backlink
+    testit "add_deleted_dangling_backlink" add_deleted_dangling_backlink
+    testit "revive_links_on_deleted_group" revive_links_on_deleted_group
+    testit "revive_backlink_on_deleted_group" revive_backlink_on_deleted_group
+    testit "add_deleted_target_link" add_deleted_target_link
+    testit "add_deleted_target_backlink" add_deleted_target_backlink
+    testit "dangling_one_way_link" dangling_one_way_link
+    testit "dangling_one_way_dn" dangling_one_way_dn
+    testit "deleted_one_way_dn" deleted_one_way_dn
+    testit "add_dangling_multi_valued" add_dangling_multi_valued
+
+#Now things are set up, work with the DB
+    testit "delete_member_of_deleted_group" delete_member_of_deleted_group
+    testit "delete_backlink_memberof_deleted_group" delete_backlink_memberof_deleted_group
+    testit "delete_dangling_backlink_memberof_group" delete_dangling_backlink_memberof_group
+else
+    subunit_start_test $RELEASE
+    subunit_skip_test $RELEASE <<EOF
+no test provision
+EOF
+
+    subunit_start_test "tombstones_expunge"
+    subunit_skip_test "tombstones_expunge" <<EOF
+no test provision
+EOF
+fi
+
+if [ -d $PREFIX_ABS/${RELEASE} ]; then
+    rm -fr $PREFIX_ABS/${RELEASE}
+fi
+
+exit $failed
-- 
2.11.0


From d768ab4cfb566c98bca4c98fcaa9dad7223402ed Mon Sep 17 00:00:00 2001
From: Andrej Gessel <Andrej.Gessel at janztec.com>
Date: Thu, 19 Oct 2017 17:16:37 +0200
Subject: [PATCH 16/17] 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

Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Signed-off-by: Andrej Gessel <Andrej.Gessel at janztec.com>
---
 selftest/knownfail.d/delete_member_of_deleted_group | 1 -
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c     | 3 ++-
 2 files changed, 2 insertions(+), 2 deletions(-)
 delete mode 100644 selftest/knownfail.d/delete_member_of_deleted_group

diff --git a/selftest/knownfail.d/delete_member_of_deleted_group b/selftest/knownfail.d/delete_member_of_deleted_group
deleted file mode 100644
index f399d33ccc1..00000000000
--- a/selftest/knownfail.d/delete_member_of_deleted_group
+++ /dev/null
@@ -1 +0,0 @@
-^samba4\.blackbox\.runtime-links\.release-4-5-0-pre1\.delete_member_of_deleted_group
\ No newline at end of file
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index c7aacd83615..597e49c50f1 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -3792,7 +3792,8 @@ static int replmd_delete_remove_link(struct ldb_module *module,
 		ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
 					    msg->dn, attrs,
 					    DSDB_FLAG_NEXT_MODULE |
-					    DSDB_SEARCH_SHOW_EXTENDED_DN,
+					    DSDB_SEARCH_SHOW_EXTENDED_DN |
+					    DSDB_SEARCH_SHOW_RECYCLED,
 					    parent);
 
 		if (ret != LDB_SUCCESS) {
-- 
2.11.0


From 322d9ad0c92847148a2c5aa18c3080a26680dff5 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Wed, 1 Nov 2017 08:22:22 +1300
Subject: [PATCH 17/17] 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.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095
---
 selftest/knownfail.d/runtime-links              |  2 --
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 44 ++++++++++++++++++++-----
 2 files changed, 36 insertions(+), 10 deletions(-)
 delete mode 100644 selftest/knownfail.d/runtime-links

diff --git a/selftest/knownfail.d/runtime-links b/selftest/knownfail.d/runtime-links
deleted file mode 100644
index 70de8be3d55..00000000000
--- a/selftest/knownfail.d/runtime-links
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba4\.blackbox\.runtime-links\.release-4-5-0-pre1\.delete_backlink_memberof_deleted_group
-^samba4\.blackbox\.runtime-links\.release-4-5-0-pre1\.delete_dangling_backlink_memberof_group
\ No newline at end of file
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 597e49c50f1..198ac84c730 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);
@@ -4275,6 +4288,7 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 				/* don't remove the rDN */
 				continue;
 			}
+
 			if (sa->linkID & 1) {
 				/*
 				  we have a backlink in this object
@@ -4288,7 +4302,16 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 								replmd_private,
 								old_dn, &guid,
 								el, sa, req);
-				if (ret != LDB_SUCCESS) {
+				if (ret == LDB_SUCCESS) {
+					/*
+					 * now we continue, which means we
+					 * won't remove this backlink
+					 * directly
+					 */
+					continue;
+				}
+
+				if (ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
 					const char *old_dn_str
 						= ldb_dn_get_linearized(old_dn);
 					ldb_asprintf_errstring(ldb,
@@ -4301,11 +4324,16 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 					talloc_free(tmp_ctx);
 					return LDB_ERR_OPERATIONS_ERROR;
 				}
-				/* now we continue, which means we
-				   won't remove this backlink
-				   directly
-				*/
-				continue;
+
+				/*
+				 * Otherwise vanish the link, we are
+				 * out of sync and the controlling
+				 * object does not have the source
+				 * link any more
+				 */
+
+				dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
+
 			} else if (sa->linkID == 0) {
 				if (ldb_attr_in_list(preserved_attrs, el->name)) {
 					continue;
-- 
2.11.0

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 862 bytes
Desc: This is a digitally signed message part
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20171124/8b9115d3/signature-0001.sig>


More information about the samba-technical mailing list