]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
dsdb: Allow delete (directly and over DRS) of an object with a link to itself
authorAndrew Bartlett <abartlet@samba.org>
Mon, 2 Mar 2020 05:01:29 +0000 (18:01 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Sun, 22 Mar 2020 04:39:36 +0000 (04:39 +0000)
Previously this would fail with Unsupported critical extension 1.3.6.1.4.1.7165.4.3.2

Reported by Alexander Harm.  Many thanks for helping make Samba better
and for your patience with patches and providing debugging information.

REF: https://lists.samba.org/archive/samba/2020-February/228153.html
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14306

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
selftest/knownfail.d/dbcheck-links [deleted file]
selftest/knownfail.d/dsdb-link-to-self [deleted file]
source4/dsdb/samdb/ldb_modules/repl_meta_data.c

diff --git a/selftest/knownfail.d/dbcheck-links b/selftest/knownfail.d/dbcheck-links
deleted file mode 100644 (file)
index 312afb5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba4.blackbox.dbcheck-links.release-4-5-0-pre1.dangling_link_to_unknown_does_not_prevent_delete
-^samba4.blackbox.dbcheck-links.release-4-5-0-pre1.dangling_link_to_known_and_unknown_does_not_prevent_delete
diff --git a/selftest/knownfail.d/dsdb-link-to-self b/selftest/knownfail.d/dsdb-link-to-self
deleted file mode 100644 (file)
index 2d4383a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-^samba4.ldap.linked_attributes.python\(.*\).__main__.LATests.test_self_link
\ No newline at end of file
index 589323ca320efe4cf73e8709e3e10edad254945d..97c08a2ffcdf47ce96731102a840508400c8a7d8 100644 (file)
@@ -4025,7 +4025,8 @@ static int replmd_delete_remove_link(struct ldb_module *module,
                                     struct GUID *guid,
                                     struct ldb_message_element *el,
                                     const struct dsdb_attribute *sa,
-                                    struct ldb_request *parent)
+                                    struct ldb_request *parent,
+                                    bool *caller_should_vanish)
 {
        unsigned int i;
        TALLOC_CTX *tmp_ctx = talloc_new(module);
@@ -4065,7 +4066,6 @@ static int replmd_delete_remove_link(struct ldb_module *module,
                        return LDB_ERR_OPERATIONS_ERROR;
                }
 
-
                msg->dn = dsdb_dn->dn;
 
                target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
@@ -4089,6 +4089,16 @@ static int replmd_delete_remove_link(struct ldb_module *module,
                                            DSDB_SEARCH_SHOW_RECYCLED,
                                            parent);
 
+               if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+                       DBG_WARNING("Failed to find forward link object %s "
+                                   "to remove backlink %s on %s",
+                                   ldb_dn_get_linearized(msg->dn),
+                                   sa->lDAPDisplayName,
+                                   ldb_dn_get_linearized(dn));
+                       *caller_should_vanish = true;
+                       continue;
+               }
+
                if (ret != LDB_SUCCESS) {
                        talloc_free(tmp_ctx);
                        return ret;
@@ -4098,8 +4108,14 @@ static int replmd_delete_remove_link(struct ldb_module *module,
                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;
+                       DBG_WARNING("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));
+                       *caller_should_vanish = true;
+                       continue;
                }
 
                /*
@@ -4129,17 +4145,29 @@ static int replmd_delete_remove_link(struct ldb_module *module,
                }
 
                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;
+                       DBG_WARNING("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));
+                       *caller_should_vanish = true;
+                       continue;
                }
 
+               /*
+                * If we find a backlink to ourself, we will delete
+                * the forward link before we get to process that
+                * properly, so just let the caller process this via
+                * the forward link.
+                *
+                * We do this once we are sure we have the forward
+                * link (to ourself) in case something is very wrong
+                * and they are out of sync.
+                */
+               if (ldb_dn_compare(dsdb_dn->dn, dn) == 0) {
+                       continue;
+               }
 
                /* This needs to get the Binary DN, by first searching */
                dn_str = dsdb_dn_get_linearized(tmp_ctx,
@@ -4621,6 +4649,7 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
                        }
 
                        if (sa->linkID & 1) {
+                               bool caller_should_vanish = false;
                                /*
                                 * we have a backlink in this object
                                 * that needs to be removed. We're not
@@ -4632,17 +4661,9 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
                                ret = replmd_delete_remove_link(module, schema,
                                                                replmd_private,
                                                                old_dn, &guid,
-                                                               el, sa, req);
-                               if (ret == LDB_SUCCESS) {
-                                       /*
-                                        * now we continue, which means we
-                                        * won't remove this backlink
-                                        * directly
-                                        */
-                                       continue;
-                               }
-
-                               if (ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
+                                                               el, sa, req,
+                                                               &caller_should_vanish);
+                               if (ret != LDB_SUCCESS) {
                                        const char *old_dn_str
                                                = ldb_dn_get_linearized(old_dn);
                                        ldb_asprintf_errstring(ldb,
@@ -4656,6 +4677,15 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request
                                        return LDB_ERR_OPERATIONS_ERROR;
                                }
 
+                               if (caller_should_vanish == false) {
+                                       /*
+                                        * 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