summaryrefslogtreecommitdiff
path: root/source4/dsdb
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb')
-rw-r--r--source4/dsdb/repl/replicated_objects.c11
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c118
-rw-r--r--source4/dsdb/samdb/samdb.h1
3 files changed, 129 insertions, 1 deletions
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index 481ff60217..ec4dffe0be 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 49fca5f376..1dc7ea057c 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 3e2f4a2e79..5422218059 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;
};