From 9b1589e2a01df0e2c98299da7244f962c882c833 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 | 65 +++++++++++++++++++------ 1 file changed, 49 insertions(+), 16 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..f591759 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3159,15 +3159,17 @@ 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 +3184,9 @@ 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 +3194,10 @@ 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; } @@ -3217,29 +3221,48 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request */ if (deletion_state == OBJECT_NOT_DELETED) { + struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn); + char *parent_dn_str = NULL; + /* we need the storage form of the parent GUID */ ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res, - ldb_dn_get_parent(tmp_ctx, old_dn), NULL, + parent_dn, NULL, DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | DSDB_SEARCH_REVEAL_INTERNALS| DSDB_SEARCH_SHOW_RECYCLED, req); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb_module_get_ctx(module), - "repmd_delete: Failed to %s %s, because we failed to find it's parent (%s): %s", + "repmd_delete: Failed to %s %s, " + "because we failed to find it's parent (%s): %s", re_delete ? "re-delete" : "delete", ldb_dn_get_linearized(old_dn), - ldb_dn_get_linearized(ldb_dn_get_parent(tmp_ctx, old_dn)), + ldb_dn_get_linearized(parent_dn), ldb_errstring(ldb_module_get_ctx(module))); talloc_free(tmp_ctx); return ret; } + /* + * Now we can use the DB version, + * it will have the extended DN info in it + */ + parent_dn = parent_res->msgs[0]->dn; + parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx, + parent_dn, + 1); + if (parent_dn_str == NULL) { + talloc_free(tmp_ctx); + return ldb_module_oom(module); + } + ret = ldb_msg_add_steal_string(msg, "lastKnownParent", - ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1)); + parent_dn_str); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n")); - ldb_module_oom(module); + ldb_asprintf_errstring(ldb, __location__ + ": Failed to add lastKnownParent " + "string when deleting %s", + ldb_dn_get_linearized(old_dn)); talloc_free(tmp_ctx); return ret; } @@ -3248,8 +3271,10 @@ 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 +3341,14 @@ 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) { + const char *old_dn_str + = ldb_dn_get_linearized(old_dn); + ldb_asprintf_errstring(ldb, + __location__ + ": Failed to remove backlink of " + "%s when deleting %s", + el->name, + old_dn_str); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } From f1dc8a041bc3377b58b6ed282fc5ff4e3f866138 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 | 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 f591759..03dc5c8 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,18 @@ 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; + 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 +2931,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 +2946,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; @@ -3149,10 +3189,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, @@ -3330,7 +3370,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 @@ -3339,7 +3379,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); @@ -3357,8 +3399,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; }