From 8b32d9ad2de96679108fd7bffe804da10a652b2f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 6 Jul 2012 15:35:42 +1000 Subject: [PATCH] s4-dsdb: Use parent_object_guid to find the correct parent for new objects This allows the parent to be renmaed while a new object is added on another replica. This rename may also be a delete, in which case we must move it to lostandfound. Andrew Bartlett --- source4/dsdb/repl/replicated_objects.c | 11 +++ source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 118 +++++++++++++++++++++++- source4/dsdb/samdb/samdb.h | 1 + 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index 481ff60217c..ec4dffe0be9 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -203,6 +203,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb, struct ldb_message *msg; struct replPropertyMetaDataBlob *md; struct ldb_val guid_value; + struct ldb_val parent_guid_value; NTTIME whenChanged = 0; time_t whenChanged_t; const char *whenChanged_s; @@ -375,8 +376,18 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb, return ntstatus_to_werror(nt_status); } + if (in->parent_object_guid) { + nt_status = GUID_to_ndr_blob(in->parent_object_guid, msg, &parent_guid_value); + if (!NT_STATUS_IS_OK(nt_status)) { + return ntstatus_to_werror(nt_status); + } + } else { + parent_guid_value = data_blob_null; + } + out->msg = msg; out->guid_value = guid_value; + out->parent_guid_value = parent_guid_value; out->when_changed = whenChanged_s; out->meta_data = md; return WERR_OK; diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 49fca5f376e..1dc7ea057c6 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3671,6 +3671,122 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) return ldb_next_request(ar->module, change_req); } +static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct replmd_replicated_request *ar = talloc_get_type(req->context, + struct replmd_replicated_request); + int ret; + + if (!ares) { + return ldb_module_done(ar->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS && + ares->error != LDB_ERR_NO_SUCH_OBJECT) { + return ldb_module_done(ar->req, ares->controls, + ares->response, ares->error); + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + { + struct ldb_message *parent_msg = ares->message; + struct ldb_message *msg = ar->objs->objects[ar->index_current].msg; + struct ldb_dn *parent_dn; + int comp_num = ldb_dn_get_comp_num(msg->dn); + if (comp_num > 1) { + if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) { + talloc_free(ares); + return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module)); + } + } + if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE") + && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) { + /* Per MS-DRSR 4.1.10.6.10 + * FindBestParentObject we need to move this + * new object under a deleted object to + * lost-and-found */ + + ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg, + ldb_get_default_basedn(ldb_module_get_ctx(ar->module)), + DS_GUID_LOSTANDFOUND_CONTAINER, + &parent_dn); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module)); + } + } else { + parent_dn = parent_msg->dn; + } + if (!ldb_dn_add_base(msg->dn, parent_dn)) { + talloc_free(ares); + return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module)); + } + break; + } + case LDB_REPLY_REFERRAL: + /* we ignore referrals */ + break; + + case LDB_REPLY_DONE: + ret = replmd_replicated_apply_add(ar); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ar->req, NULL, NULL, ret); + } + } + + talloc_free(ares); + return LDB_SUCCESS; +} + +/* + * Look for the parent object, so we put the new object in the right place + */ + +static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar) +{ + struct ldb_context *ldb; + int ret; + char *tmp_str; + char *filter; + struct ldb_request *search_req; + static const char *attrs[] = {"isDeleted", NULL}; + + ldb = ldb_module_get_ctx(ar->module); + + if (!ar->objs->objects[ar->index_current].parent_guid_value.data) { + return replmd_replicated_apply_add(ar); + } + + tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value); + if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM); + + filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str); + if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM); + talloc_free(tmp_str); + + ret = ldb_build_search_req(&search_req, + ldb, + ar, + ar->objs->partition_dn, + LDB_SCOPE_SUBTREE, + filter, + attrs, + NULL, + ar, + replmd_replicated_apply_search_for_parent_callback, + ar->req); + LDB_REQ_SET_LOCATION(search_req); + + ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID, + true, NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + + return ldb_next_request(ar->module, search_req); +} + /* handle renames that come in over DRS replication */ @@ -3964,7 +4080,7 @@ static int replmd_replicated_apply_search_callback(struct ldb_request *req, if (ar->search_msg != NULL) { ret = replmd_replicated_apply_merge(ar); } else { - ret = replmd_replicated_apply_add(ar); + ret = replmd_replicated_apply_search_for_parent(ar); } if (ret != LDB_SUCCESS) { return ldb_module_done(ar->req, NULL, NULL, ret); diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 3e2f4a2e792..5422218059f 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -129,6 +129,7 @@ struct dsdb_control_password_change { struct dsdb_extended_replicated_object { struct ldb_message *msg; struct ldb_val guid_value; + struct ldb_val parent_guid_value; const char *when_changed; struct replPropertyMetaDataBlob *meta_data; }; -- 2.11.4.GIT