summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c217
1 files changed, 141 insertions, 76 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 651cdf1c04..5fc71ab1d2 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -94,6 +94,8 @@ struct replmd_replicated_request {
bool is_urgent;
};
+static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
+
enum urgent_situation {
REPL_URGENT_ON_CREATE = 1,
REPL_URGENT_ON_UPDATE = 2,
@@ -3866,7 +3868,11 @@ static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
break;
case LDB_REPLY_DONE:
- ret = replmd_replicated_apply_add(ar);
+ if (ar->search_msg != NULL) {
+ ret = replmd_replicated_apply_merge(ar);
+ } else {
+ ret = replmd_replicated_apply_add(ar);
+ }
if (ret != LDB_SUCCESS) {
return ldb_module_done(ar->req, NULL, NULL, ret);
}
@@ -3892,7 +3898,11 @@ static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_re
ldb = ldb_module_get_ctx(ar->module);
if (!ar->objs->objects[ar->index_current].parent_guid_value.data) {
- return replmd_replicated_apply_add(ar);
+ if (ar->search_msg != NULL) {
+ return replmd_replicated_apply_merge(ar);
+ } else {
+ return replmd_replicated_apply_add(ar);
+ }
}
tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value);
@@ -3931,84 +3941,52 @@ static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_re
*/
static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
struct ldb_message *msg,
- struct replPropertyMetaDataBlob *rmd,
- struct replPropertyMetaDataBlob *omd,
- struct ldb_request *parent,
- bool *renamed)
+ struct ldb_request *parent)
{
- struct replPropertyMetaData1 *md_remote;
- struct replPropertyMetaData1 *md_local;
-
- *renamed = true;
-
- if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
- /* no rename */
- return LDB_SUCCESS;
- }
-
- /* now we need to check for double renames. We could have a
- * local rename pending which our replication partner hasn't
- * received yet. We choose which one wins by looking at the
- * attribute stamps on the two objects, the newer one wins
- */
- md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
- md_local = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
- /* if there is no name attribute then we have to assume the
- object we've received is in fact newer */
- if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING ||
- !md_remote || !md_local ||
- replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
- struct ldb_request *req;
- int ret;
- TALLOC_CTX *tmp_ctx = talloc_new(msg);
- struct ldb_result *res;
-
- DEBUG(4,("replmd_replicated_request rename %s => %s\n",
- ldb_dn_get_linearized(ar->search_msg->dn),
- ldb_dn_get_linearized(msg->dn)));
-
+ struct ldb_request *req;
+ int ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(msg);
+ struct ldb_result *res;
- res = talloc_zero(tmp_ctx, struct ldb_result);
- if (!res) {
- talloc_free(tmp_ctx);
- return ldb_oom(ldb_module_get_ctx(ar->module));
- }
-
- /* pass rename to the next module
- * so it doesn't appear as an originating update */
- ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ar->module), tmp_ctx,
- ar->search_msg->dn, msg->dn,
- NULL,
- ar,
- replmd_op_rename_callback,
- parent);
- LDB_REQ_SET_LOCATION(req);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
- }
+ DEBUG(4,("replmd_replicated_request rename %s => %s\n",
+ ldb_dn_get_linearized(ar->search_msg->dn),
+ ldb_dn_get_linearized(msg->dn)));
- ret = dsdb_request_add_controls(req, DSDB_MODIFY_RELAX);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
- }
- ret = ldb_next_request(ar->module, req);
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ if (!res) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb_module_get_ctx(ar->module));
+ }
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
+ /* pass rename to the next module
+ * so it doesn't appear as an originating update */
+ ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ar->module), tmp_ctx,
+ ar->search_msg->dn, msg->dn,
+ NULL,
+ ar,
+ replmd_op_rename_callback,
+ parent);
+ LDB_REQ_SET_LOCATION(req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = dsdb_request_add_controls(req, DSDB_MODIFY_RELAX);
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
- /* we're going to keep our old object */
- DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
- ldb_dn_get_linearized(ar->search_msg->dn),
- ldb_dn_get_linearized(msg->dn)));
- return LDB_SUCCESS;
+ ret = ldb_next_request(ar->module, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
}
@@ -4062,9 +4040,22 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
"isDeleted", false);
- /* handle renames that come in over DRS */
- ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd,
- ar->req, &renamed);
+ if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0) {
+ ret = LDB_SUCCESS;
+ } else {
+ /*
+ * handle renames, even just by case that come in over
+ * DRS. Changes in the parent DN don't hit us here,
+ * because the search for a parent will clean up those
+ * components.
+ *
+ * We also have already filtered out the case where
+ * the peer has an older name to what we have (see
+ * replmd_replicated_apply_search_callback())
+ */
+ renamed = true;
+ ret = replmd_replicated_handle_rename(ar, msg, ar->req);
+ }
/*
* This particular error code means that we already tried the
@@ -4348,17 +4339,91 @@ static int replmd_replicated_apply_search_callback(struct ldb_request *req,
break;
case LDB_REPLY_DONE:
+ {
+ struct replPropertyMetaData1 *md_remote;
+ struct replPropertyMetaData1 *md_local;
+
+ struct replPropertyMetaDataBlob omd;
+ const struct ldb_val *omd_value;
+ struct replPropertyMetaDataBlob *rmd;
+ struct ldb_message *msg;
+
ar->objs->objects[ar->index_current].last_known_parent = NULL;
- if (ar->search_msg != NULL) {
- ret = replmd_replicated_apply_merge(ar);
- } else {
+ /*
+ * This is the ADD case, find the appropriate parent,
+ * as this object doesn't exist locally:
+ */
+ if (ar->search_msg == NULL) {
ret = replmd_replicated_apply_search_for_parent(ar);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, NULL, NULL, ret);
+ }
+ talloc_free(ares);
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * Otherwise, in the MERGE case, work out if we are
+ * attempting a rename, and if so find the parent the
+ * newly renamed object wants to belong under (which
+ * may not be the parent in it's attached string DN
+ */
+ rmd = ar->objs->objects[ar->index_current].meta_data;
+ ZERO_STRUCT(omd);
+ omd.version = 1;
+
+ /* find existing meta data */
+ omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
+ if (omd_value) {
+ enum ndr_err_code ndr_err;
+ ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
+ (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
+ return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
+ }
+
+ if (omd.version != 1) {
+ return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
+ }
+ }
+
+ /*
+ * now we need to check for double renames. We could have a
+ * local rename pending which our replication partner hasn't
+ * received yet. We choose which one wins by looking at the
+ * attribute stamps on the two objects, the newer one wins
+ */
+ md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
+ md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
+ /* if there is no name attribute then we have to assume the
+ object we've received is in fact newer */
+ if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING ||
+ !md_remote || !md_local ||
+ replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
+ ret = replmd_replicated_apply_search_for_parent(ar);
+ } else {
+ msg = ar->objs->objects[ar->index_current].msg;
+
+ /* Otherwise, just merge on the existing object, force no rename */
+ DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
+ ldb_dn_get_linearized(ar->search_msg->dn),
+ ldb_dn_get_linearized(msg->dn)));
+
+ /*
+ * This assignment ensures that the strcmp()
+ * in replmd_replicated_apply_merge() avoids
+ * the rename call
+ */
+ msg->dn = ar->search_msg->dn;
+ ret = replmd_replicated_apply_merge(ar);
}
if (ret != LDB_SUCCESS) {
return ldb_module_done(ar->req, NULL, NULL, ret);
}
}
+ }
talloc_free(ares);
return LDB_SUCCESS;