From e27ce3939234887de1fb04c43603c74c7cb988b4 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 12 Oct 2015 15:51:37 +1300 Subject: [PATCH] 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 --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 75 +++++++++++++++++++------ 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 39beea9..1a09243 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3132,6 +3132,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) @@ -3142,14 +3143,19 @@ static int replmd_delete_remove_link(struct ldb_module *module, for (i=0; inum_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; @@ -3161,12 +3167,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) { @@ -3182,14 +3182,54 @@ 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); + + 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; @@ -3432,10 +3472,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, @@ -3612,7 +3652,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 @@ -3621,7 +3661,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); @@ -3640,8 +3682,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