[PATCH] Fix dn+binary linked attribute behavior (bug 11139)

Bob Campbell bobcampbell at catalyst.net.nz
Thu Feb 2 22:03:50 UTC 2017


Hi Metze,

Attached patches have these three issues fixed.

Thanks for having a look at these,
Bob


On 02/02/17 20:39, Stefan Metzmacher wrote:
> Hi Bob,
>
>> +	ret = samldb_unique_attr_check(ac, "linkID", NULL,
>> +				       ldb_get_schema_basedn(
>> +					     ldb_module_get_ctx(ac->module)));
> Can you please use helper variables instead of passing
> function calls as arguments?
>
> The commit [PATCH 3/4] torture/drs: Add a test for dn+binary linked
> attributes
> seems to have unrelated changes, can you split the domainFunctionality
> change to a separate commit? I guess the source4/selftest/tests.py
> change can also move to that commit.
>
> The test seems to be written before commit
> 207fa2331831f570eb4855e98b676782d2008f34,
> I guess you need to apply the same logic in order to avoid oid conflicts.
>
> Otherwise it looks good.
>
> Thanks!
> metze
>
>
>
>

-------------- next part --------------
From 9ef5c2a2969ccbf858e34ebea534cdeab069032f Mon Sep 17 00:00:00 2001
From: Bob Campbell <bobcampbell at catalyst.net.nz>
Date: Wed, 1 Feb 2017 12:37:21 +1300
Subject: [PATCH 1/5] python/tests: add test for duplicate linkID

The only valid duplicate linkID should be 0, since this signifies that
the link has no backlink.

Signed-off-by: Bob Campbell <bobcampbell at catalyst.net.nz>
---
 selftest/knownfail                       |  1 +
 source4/dsdb/tests/python/ldap_schema.py | 82 ++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/selftest/knownfail b/selftest/knownfail
index d96e238..72e3c3a 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -312,3 +312,4 @@
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_add_duplicate_different_type.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_rank_none.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_security_descriptor.*
+^samba4.ldap_schema.python*.*SchemaTests.test_duplicate_linkID.*
diff --git a/source4/dsdb/tests/python/ldap_schema.py b/source4/dsdb/tests/python/ldap_schema.py
index c920296..3a81181 100755
--- a/source4/dsdb/tests/python/ldap_schema.py
+++ b/source4/dsdb/tests/python/ldap_schema.py
@@ -344,6 +344,88 @@ systemOnly: FALSE
         except LdbError, (enum, estr):
             self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
 
+    def test_duplicate_linkID(self):
+        """Testing creating a duplicate linked attribute"""
+        rand = str(random.randint(1,100000))
+        attr_name = "test-duplicate-link" + time.strftime("%s", time.gmtime()) + "-" + rand
+        attr_ldap_display_name = attr_name.replace("-", "")
+        attributeID = "1.3.6.1.4.1.7165.4.6.1.6.15." + rand
+        linkID = "94852"
+        ldif = """
+dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
+objectClass: top
+objectClass: attributeSchema
+adminDescription: """ + attr_name + """
+adminDisplayName: """ + attr_name + """
+cn: """ + attr_name + """
+attributeId: """ + attributeID + """
+linkId: """ + linkID + """
+attributeSyntax: 2.5.5.12
+omSyntax: 64
+instanceType: 4
+isSingleValued: TRUE
+systemOnly: FALSE
+"""
+        self.ldb.add_ldif(ldif)
+
+        ldif = """
+dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
+objectClass: top
+objectClass: attributeSchema
+adminDescription: """ + attr_name + """dup
+adminDisplayName: """ + attr_name + """dup
+cn: """ + attr_name + """-dup
+attributeId: """ + attributeID + "1" + """
+linkID: """ + linkID + """
+attributeSyntax: 2.5.5.12
+omSyntax: 64
+instanceType: 4
+isSingleValued: TRUE
+systemOnly: FALSE
+"""
+        try:
+            self.ldb.add_ldif(ldif)
+            self.fail("Should have failed to add duplicate linkID value")
+        except LdbError, (enum, estr):
+            self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
+
+        # We should be able to add two links both with linkID=0
+        attr_name = "test-duplicate-link-ID0" + time.strftime("%s", time.gmtime()) + "-" + rand
+        attr_ldap_display_name = attr_name.replace("-", "")
+        attributeID = "1.3.6.1.4.1.7165.4.6.1.6.16." + rand
+        ldif = """
+dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
+objectClass: top
+objectClass: attributeSchema
+adminDescription: """ + attr_name + """
+adminDisplayName: """ + attr_name + """
+cn: """ + attr_name + """
+attributeId: """ + attributeID + "2" + """
+linkId: 0
+attributeSyntax: 2.5.5.12
+omSyntax: 64
+instanceType: 4
+isSingleValued: TRUE
+systemOnly: FALSE
+"""
+        self.ldb.add_ldif(ldif)
+
+        ldif = """
+dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
+objectClass: top
+objectClass: attributeSchema
+adminDescription: """ + attr_name + """dup
+adminDisplayName: """ + attr_name + """dup
+cn: """ + attr_name + """-dup
+attributeId: """ + attributeID + "3" + """
+linkID: 0
+attributeSyntax: 2.5.5.12
+omSyntax: 64
+instanceType: 4
+isSingleValued: TRUE
+systemOnly: FALSE
+"""
+        self.ldb.add_ldif(ldif)
 
     def test_duplicate_attributeID_governsID(self):
         """Testing creating a duplicate attribute and class"""
-- 
1.9.1


From de00b3fefdf34bde99a55ebb38b943ad55c2ff77 Mon Sep 17 00:00:00 2001
From: Bob Campbell <bobcampbell at catalyst.net.nz>
Date: Wed, 1 Feb 2017 11:54:40 +1300
Subject: [PATCH 2/5] samldb: Prevent duplicate linkID in schema

Previously, we could run into issues when trying to delete backlinks with
duplicate linkIDs. The deletion code could try to follow the incorrect
attribute, thus failing to remove the backlink.

Signed-off-by: Bob Campbell <bobcampbell at catalyst.net.nz>
Pair-programmed-with: Andrew Bartlett <abartlet at samba.org>
---
 selftest/knownfail                      |  1 -
 source4/dsdb/samdb/ldb_modules/samldb.c | 36 +++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 72e3c3a..d96e238 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -312,4 +312,3 @@
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_add_duplicate_different_type.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_rank_none.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_security_descriptor.*
-^samba4.ldap_schema.python*.*SchemaTests.test_duplicate_linkID.*
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index b33cf24..6792b2a 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -272,6 +272,37 @@ static int samldb_schema_ldapdisplayname_valid_check(struct samldb_ctx *ac)
 	return ret;
 }
 
+static int samldb_schema_linkid_valid_check(struct samldb_ctx *ac)
+{
+	int ret;
+	bool is_zero;
+	struct ldb_message_element *el;
+	const char *enc_str;
+	struct ldb_dn *schema_dn;
+
+	el = dsdb_get_single_valued_attr(ac->msg, "linkID",
+					 ac->req->operation);
+	if (el == NULL) {
+		return LDB_SUCCESS;
+	}
+
+	enc_str = ldb_binary_encode(ac, el->values[0]);
+	if (enc_str == NULL) {
+		return ldb_module_oom(ac->module);
+	}
+
+	is_zero = strcmp(enc_str, "0") == 0;
+	if (is_zero) {
+		return LDB_SUCCESS;
+	}
+
+	schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
+	ret = samldb_unique_attr_check(ac, "linkID", NULL, schema_dn);
+	if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+		ret = LDB_ERR_UNWILLING_TO_PERFORM;
+	}
+	return ret;
+}
 
 /* sAMAccountName handling */
 
@@ -3227,6 +3258,11 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req)
 			if (ret != LDB_SUCCESS) {
 				return ret;
 			}
+
+			ret = samldb_schema_linkid_valid_check(ac);
+			if (ret != LDB_SUCCESS) {
+				return ret;
+			}
 		}
 
 		ret = samldb_schema_ldapdisplayname_valid_check(ac);
-- 
1.9.1


From c027feba9656a3220e816c757afc76358ca18058 Mon Sep 17 00:00:00 2001
From: Bob Campbell <bobcampbell at catalyst.net.nz>
Date: Fri, 3 Feb 2017 10:33:54 +1300
Subject: [PATCH 3/5] torture/drs: run repl_schema in fl2000dc environment as
 well

This will be necessary as linked attributes are handled differently in
Windows 2000.
We also only check msDS-IntId if we have a functional level of > Windows
2000, as this attribute is not present on lower domain function levels.

Signed-off-by: Bob Campbell <bobcampbell at catalyst.net.nz>
---
 source4/selftest/tests.py                 | 11 ++++++-----
 source4/torture/drs/python/repl_schema.py | 20 +++++++++++++-------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 98974dc..94d19f3 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -683,11 +683,6 @@ for env in ['vampire_dc', 'promoted_dc']:
                            extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
                            environ={'DC1': "$DC_SERVER", 'DC2': '$%s_SERVER' % env.upper()},
                            extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
-    planoldpythontestsuite(env, "repl_schema",
-                           extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
-                           name="samba4.drs.repl_schema.python(%s)" % env,
-                           environ={'DC1': "$DC_SERVER", 'DC2': '$%s_SERVER' % env.upper()},
-                           extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
     planoldpythontestsuite(env, "repl_move",
                            extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
                            name="samba4.drs.repl_move.python(%s)" % env,
@@ -704,6 +699,12 @@ for env in ['vampire_dc', 'promoted_dc']:
                            environ={'DC1': "$DC_SERVER", 'DC2': '$%s_SERVER' % env.upper()},
                            extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
 
+for env in ['vampire_dc', 'promoted_dc', 'fl2000dc']:
+    planoldpythontestsuite(env, "repl_schema",
+                           extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
+                           name="samba4.drs.repl_schema.python(%s)" % env,
+                           environ={'DC1': "$DC_SERVER", 'DC2': '$%s_SERVER' % env.upper()},
+                           extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
 
 planoldpythontestsuite("chgdcpass:local", "samba.tests.blackbox.samba_dnsupdate",
                        environ={'DNS_SERVER_IP': '$SERVER_IP'})
diff --git a/source4/torture/drs/python/repl_schema.py b/source4/torture/drs/python/repl_schema.py
index 865260c..3488296 100644
--- a/source4/torture/drs/python/repl_schema.py
+++ b/source4/torture/drs/python/repl_schema.py
@@ -43,6 +43,7 @@ import ldb
 import drs_base
 from samba.dcerpc import drsuapi, misc
 from samba.drs_utils import drs_DsBind
+from samba import dsdb
 
 class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
 
@@ -262,14 +263,19 @@ class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
         self._check_object(c_dn)
         self._check_object(a_dn)
 
-        res = self.ldb_dc1.search(base=a_dn,
+        res = self.ldb_dc1.search(base="",
                                   scope=SCOPE_BASE,
-                                  attrs=["msDS-IntId"])
-        self.assertEqual(1, len(res))
-        self.assertTrue("msDS-IntId" in res[0])
-        int_id = int(res[0]["msDS-IntId"][0])
-        if int_id < 0:
-            int_id += (1 << 32)
+                                  attrs=["domainFunctionality"])
+
+        if int(res[0]["domainFunctionality"][0]) > dsdb.DS_DOMAIN_FUNCTION_2000:
+            res = self.ldb_dc1.search(base=a_dn,
+                                      scope=SCOPE_BASE,
+                                      attrs=["msDS-IntId"])
+            self.assertEqual(1, len(res))
+            self.assertTrue("msDS-IntId" in res[0])
+            int_id = int(res[0]["msDS-IntId"][0])
+            if int_id < 0:
+                int_id += (1 << 32)
 
         dc_guid_1 = self.ldb_dc1.get_invocation_id()
 
-- 
1.9.1


From 8d88d0320e5ef89791ccc30f14758ac6958d702b Mon Sep 17 00:00:00 2001
From: Bob Campbell <bobcampbell at catalyst.net.nz>
Date: Fri, 3 Feb 2017 10:34:14 +1300
Subject: [PATCH 4/5] torture/drs: Add a test for dn+binary linked attributes

---
 selftest/knownfail                        |  2 +
 source4/torture/drs/python/repl_schema.py | 89 +++++++++++++++++++++++++++++--
 2 files changed, 87 insertions(+), 4 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index d96e238..1f659c8 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -312,3 +312,5 @@
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_add_duplicate_different_type.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_rank_none.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_security_descriptor.*
+#we don't properly handle deleting dn+binary linked attributes
+^samba4.drs.repl_schema.python.*repl_schema.DrsReplSchemaTestCase.test_classWithCustomBinaryDNLinkAttribute.*
diff --git a/source4/torture/drs/python/repl_schema.py b/source4/torture/drs/python/repl_schema.py
index 3488296..4caea85 100644
--- a/source4/torture/drs/python/repl_schema.py
+++ b/source4/torture/drs/python/repl_schema.py
@@ -29,6 +29,8 @@
 
 import time
 import random
+import ldb
+import drs_base
 
 from ldb import (
     ERR_NO_SUCH_OBJECT,
@@ -36,11 +38,8 @@ from ldb import (
     SCOPE_BASE,
     Message,
     FLAG_MOD_ADD,
-    FLAG_MOD_REPLACE,
+    FLAG_MOD_REPLACE
     )
-import ldb
-
-import drs_base
 from samba.dcerpc import drsuapi, misc
 from samba.drs_utils import drs_DsBind
 from samba import dsdb
@@ -356,3 +355,85 @@ class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
         # check objects are replicated
         self._check_object(c_dn)
         self._check_object(a_dn)
+
+    def test_classWithCustomBinaryDNLinkAttribute(self):
+        linkID = 99992
+        found = False
+        tries = 0
+
+        while tries < 10:
+            try:
+                linkID += 2
+                tries += 1
+
+                # Add a new attribute to the schema, which has binary DN syntax (2.5.5.7)
+                (bin_ldn, bin_dn) = self._schema_new_attr(self.ldb_dc1, "attr-Link-Bin", 18,
+                                                          attrs={"linkID": str(linkID),
+                                                                 "attributeSyntax": "2.5.5.7",
+                                                                 "omSyntax": "127"})
+                (bin_ldn_b, bin_dn_b) = self._schema_new_attr(self.ldb_dc1, "attr-Link-Bin-Back", 19,
+                                                              attrs={"linkID": str(linkID+1),
+                                                                     "attributeSyntax": "2.5.5.1",
+                                                                     "omSyntax": "127"})
+            except ldb.LdbError, (enum, estr):
+                if "already in use" in estr:
+                    pass
+                else:
+                    raise
+            else:
+                found = True
+                break
+
+        if not found:
+            self.fail("Failed to find open linkID.")
+
+        # Add a new class to the schema which can have the binary DN attribute
+        (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-Link-Bin", 20,
+                                               3,
+                                               {"mayContain": bin_ldn})
+        (c_ldn_b, c_dn_b) = self._schema_new_class(self.ldb_dc1, "cls-Link-Bin-Back", 21,
+                                                   3,
+                                                   {"mayContain": bin_ldn_b})
+
+        link_end_dn = ldb.Dn(self.ldb_dc1, "ou=X")
+        link_end_dn.add_base(self.ldb_dc1.get_default_basedn())
+        link_end_dn.set_component(0, "OU", bin_dn_b.get_component_value(0))
+
+        ou_dn = ldb.Dn(self.ldb_dc1, "ou=X")
+        ou_dn.add_base(self.ldb_dc1.get_default_basedn())
+        ou_dn.set_component(0, "OU", bin_dn.get_component_value(0))
+
+        # Add an instance of the class to be pointed at 
+        rec = {"dn": link_end_dn,
+               "objectClass": ["top", "organizationalUnit", c_ldn_b],
+               "ou": link_end_dn.get_component_value(0)}
+        self.ldb_dc1.add(rec)
+
+        # .. and one that does, and points to the first one
+        rec = {"dn": ou_dn,
+               "objectClass": ["top", "organizationalUnit", c_ldn],
+               "ou": ou_dn.get_component_value(0)}
+        self.ldb_dc1.add(rec)
+
+        m = Message.from_dict(self.ldb_dc1,
+                              {"dn": ou_dn,
+                               bin_ldn: "B:8:1234ABCD:%s" % str(link_end_dn)},
+                              FLAG_MOD_ADD)
+        self.ldb_dc1.modify(m)
+
+        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+                                nc_dn=self.schema_dn, forced=True)
+        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+                                nc_dn=self.domain_dn, forced=True)
+
+        self._check_object(c_dn)
+        self._check_object(bin_dn)
+
+        # Make sure we can delete the backlink
+        self.ldb_dc1.delete(link_end_dn)
+
+        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+                                nc_dn=self.schema_dn, forced=True)
+        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+                                nc_dn=self.domain_dn, forced=True)
+
-- 
1.9.1


From 998db08e1bf4020abda581ec19c13c181e0f3d88 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 12 Oct 2015 15:51:37 +1300
Subject: [PATCH 5/5] repl_meta_data: Remove the correct linked attribute
 forward link

The previous code assumed that only plain DNs could be linked attributes.

We need to look over the list of attribute values and find the value
that causes this particular backlink to exist, so we can remove it.

We do not know (until we search) of the binary portion, so we must
search over all the attribute values at this layer, using the
parsed_dn_find() routine used elsewhere in this code.

Found attempting to demote an RODC in a clone of a Windows 2012R2
domain, due to the msDS-RevealedUsers attribute.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 selftest/knownfail                              |  2 -
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 79 +++++++++++++++++++------
 2 files changed, 62 insertions(+), 19 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 1f659c8..d96e238 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -312,5 +312,3 @@
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_add_duplicate_different_type.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_rank_none.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_security_descriptor.*
-#we don't properly handle deleting dn+binary linked attributes
-^samba4.drs.repl_schema.python.*repl_schema.DrsReplSchemaTestCase.test_classWithCustomBinaryDNLinkAttribute.*
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 7d12c23..e63872d 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -3146,6 +3146,7 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
 static int replmd_delete_remove_link(struct ldb_module *module,
 				     const struct dsdb_schema *schema,
 				     struct ldb_dn *dn,
+				     struct GUID *guid,
 				     struct ldb_message_element *el,
 				     const struct dsdb_attribute *sa,
 				     struct ldb_request *parent)
@@ -3156,14 +3157,19 @@ static int replmd_delete_remove_link(struct ldb_module *module,
 
 	for (i=0; i<el->num_values; i++) {
 		struct dsdb_dn *dsdb_dn;
-		NTSTATUS status;
 		int ret;
-		struct GUID guid2;
 		struct ldb_message *msg;
 		const struct dsdb_attribute *target_attr;
 		struct ldb_message_element *el2;
+		const char *dn_str;
 		struct ldb_val dn_val;
 		uint32_t dsdb_flags = 0;
+		const char *attrs[] = { NULL, NULL };
+		struct ldb_result *link_res;
+		struct ldb_message *link_msg;
+		struct ldb_message_element *link_el;
+		struct parsed_dn *p;
+		struct parsed_dn *link_dns;
 
 		if (dsdb_dn_is_deleted_val(&el->values[i])) {
 			continue;
@@ -3175,12 +3181,6 @@ static int replmd_delete_remove_link(struct ldb_module *module,
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
 
-		status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
-		if (!NT_STATUS_IS_OK(status)) {
-			talloc_free(tmp_ctx);
-			return LDB_ERR_OPERATIONS_ERROR;
-		}
-
 		/* remove the link */
 		msg = ldb_msg_new(tmp_ctx);
 		if (!msg) {
@@ -3196,14 +3196,58 @@ static int replmd_delete_remove_link(struct ldb_module *module,
 		if (target_attr == NULL) {
 			continue;
 		}
+		attrs[0] = target_attr->lDAPDisplayName;
 
-		ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
+		ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
+					LDB_FLAG_MOD_DELETE, &el2);
 		if (ret != LDB_SUCCESS) {
 			ldb_module_oom(module);
 			talloc_free(tmp_ctx);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
-		dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
+
+		ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
+					    msg->dn, attrs,
+					    DSDB_FLAG_NEXT_MODULE, parent);
+
+		if (ret != LDB_SUCCESS) {
+			talloc_free(tmp_ctx);
+			return ret;
+		}
+
+		link_msg = link_res->msgs[0];
+		link_el = ldb_msg_find_element(link_msg,
+					       target_attr->lDAPDisplayName);
+		if (link_el == NULL) {
+			talloc_free(tmp_ctx);
+			return LDB_ERR_NO_SUCH_ATTRIBUTE;
+		}
+
+		ret = get_parsed_dns(module, tmp_ctx,
+				     link_el, &link_dns,
+				     target_attr->syntax->ldap_oid, parent);
+		if (ret != LDB_SUCCESS) {
+			talloc_free(tmp_ctx);
+			return ret;
+		}
+		p = parsed_dn_find(link_dns, link_el->num_values, guid, dn);
+		if (p == NULL) {
+			ldb_asprintf_errstring(ldb_module_get_ctx(module),
+					       "Failed to find forward link on %s "
+					       "as %s to remove backlink %s on %s",
+					       ldb_dn_get_linearized(msg->dn),
+					       target_attr->lDAPDisplayName,
+					       sa->lDAPDisplayName,
+					       ldb_dn_get_linearized(dn));
+			talloc_free(tmp_ctx);
+			return LDB_ERR_NO_SUCH_ATTRIBUTE;
+		}
+
+
+		/* This needs to get the Binary DN, by first searching */
+		dn_str = dsdb_dn_get_linearized(tmp_ctx,
+						p->dsdb_dn);
+		dn_val = data_blob_string_const(dn_str);
 		el2->values = &dn_val;
 		el2->num_values = 1;
 
@@ -3446,10 +3490,10 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 		}
 	}
 
-	if (deletion_state == OBJECT_NOT_DELETED) {
-		/* get the objects GUID from the search we just did */
-		guid = samdb_result_guid(old_msg, "objectGUID");
+	/* get the objects GUID from the search we just did */
+	guid = samdb_result_guid(old_msg, "objectGUID");
 
+	if (deletion_state == OBJECT_NOT_DELETED) {
 		/* Add a formatted child */
 		retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
 					    rdn_name,
@@ -3626,7 +3670,7 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 				/* don't remove the rDN */
 				continue;
 			}
-			if (sa->linkID && (sa->linkID & 1)) {
+			if (sa->linkID & 1) {
 				/*
 				  we have a backlink in this object
 				  that needs to be removed. We're not
@@ -3635,7 +3679,9 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 				  modify to delete the corresponding
 				  forward link
 				 */
-				ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
+				ret = replmd_delete_remove_link(module, schema,
+								old_dn, &guid,
+								el, sa, req);
 				if (ret != LDB_SUCCESS) {
 					const char *old_dn_str
 						= ldb_dn_get_linearized(old_dn);
@@ -3654,8 +3700,7 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
 				   directly
 				*/
 				continue;
-			}
-			if (!sa->linkID) {
+			} else if (sa->linkID == 0) {
 				if (ldb_attr_in_list(preserved_attrs, el->name)) {
 					continue;
 				}
-- 
1.9.1



More information about the samba-technical mailing list