From 5b5dba8f2981bf6b84a7a521d2883cf32afcbc8c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 24 Sep 2015 14:08:37 +1200 Subject: [PATCH 1/2] repl_meta_data: Print more detail into the LDB error string, not just DEBUG() Signed-off-by: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 28 +++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3310d30..5a83c68 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3159,15 +3159,15 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request ldb_dn_escape_value(tmp_ctx, *rdn_value), GUID_string(tmp_ctx, &guid)); if (!retb) { - DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s", - ldb_dn_get_linearized(new_dn))); + ldb_asprintf_errstring(ldb, __location__ ": Unable to add a formatted child to dn: %s", + ldb_dn_get_linearized(new_dn)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = ldb_msg_add_string(msg, "isDeleted", "TRUE"); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n")); + ldb_asprintf_errstring(ldb, __location__ ": Failed to add isDeleted string to the msg"); ldb_module_oom(module); talloc_free(tmp_ctx); return ret; @@ -3182,8 +3182,8 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn); retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1); if (!retb) { - DEBUG(0,(__location__ ": Unable to add a prepare rdn of %s", - ldb_dn_get_linearized(rdn))); + ldb_asprintf_errstring(ldb, __location__ ": Unable to add a prepare rdn of %s", + ldb_dn_get_linearized(rdn)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } @@ -3191,9 +3191,9 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request retb = ldb_dn_add_child(new_dn, rdn); if (!retb) { - DEBUG(0,(__location__ ": Unable to add rdn %s to base dn: %s", - ldb_dn_get_linearized(rdn), - ldb_dn_get_linearized(new_dn))); + ldb_asprintf_errstring(ldb, __location__ ": Unable to add rdn %s to base dn: %s", + ldb_dn_get_linearized(rdn), + ldb_dn_get_linearized(new_dn)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } @@ -3238,7 +3238,8 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request ret = ldb_msg_add_steal_string(msg, "lastKnownParent", ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1)); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n")); + ldb_asprintf_errstring(ldb, __location__ ": Failed to add lastKnownParent string when deleting %s", + ldb_dn_get_linearized(old_dn)); ldb_module_oom(module); talloc_free(tmp_ctx); return ret; @@ -3248,8 +3249,8 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request if (next_deletion_state == OBJECT_DELETED) { ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n")); - ldb_module_oom(module); + ldb_asprintf_errstring(ldb, __location__ ": Failed to add msDS-LastKnownRDN string when deleting %s", + ldb_dn_get_linearized(old_dn)); talloc_free(tmp_ctx); return ret; } @@ -3316,6 +3317,11 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request */ ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req); if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + __location__ + ": Failed to remove backlink of %s when deleting %s", + el->name, + ldb_dn_get_linearized(old_dn)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } From a64377cb24772859a5300a43340a1a4d39c753cb Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 12 Oct 2015 15:51:37 +1300 Subject: [PATCH 2/2] 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. Signed-off-by: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 92 +++++++++++++++++-------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 5a83c68..b7bf6d8 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2897,6 +2897,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) @@ -2907,13 +2908,17 @@ 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; struct ldb_val dn_val; + 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; @@ -2925,12 +2930,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) { @@ -2946,14 +2945,53 @@ 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_val = data_blob_string_const(dsdb_dn_get_linearized(tmp_ctx, + p->dsdb_dn)); el2->values = &dn_val; el2->num_values = 1; @@ -3149,10 +3187,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, @@ -3306,7 +3344,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 != 0 && (sa->linkID & 1)) { /* we have a backlink in this object that needs to be removed. We're not @@ -3315,23 +3353,17 @@ 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); - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, - __location__ - ": Failed to remove backlink of %s when deleting %s", - el->name, - ldb_dn_get_linearized(old_dn)); - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; + ret = replmd_delete_remove_link(module, schema, + old_dn, &guid, + el, sa, req); + if (ret == LDB_SUCCESS) { + /* now we continue, which means we + won't remove this backlink + directly + */ + continue; } - /* now we continue, which means we - won't remove this backlink - directly - */ - continue; - } - if (!sa->linkID) { + } else if (sa->linkID == 0) { if (ldb_attr_in_list(preserved_attrs, el->name)) { continue; }