summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c270
1 files changed, 199 insertions, 71 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index b6ff7ff794..813438d739 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -2,10 +2,10 @@
ldb database library
Copyright (C) Simo Sorce 2004-2008
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
- Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
+ Copyright (C) Andrew Tridgell 2005-2009
Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
- Copyright (C) Matthieu Patou <mat@samba.org> 2010
+ Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -92,9 +92,12 @@ struct replmd_replicated_request {
uint64_t seq_num;
bool is_urgent;
+
+ bool isDeleted;
};
static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
+static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
enum urgent_situation {
REPL_URGENT_ON_CREATE = 1,
@@ -154,7 +157,7 @@ static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
}
-static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
+static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
/*
initialise the module
@@ -456,10 +459,7 @@ static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
}
if (ac->apply_mode) {
- talloc_free(ares);
- ac->index_current++;
-
- ret = replmd_replicated_apply_next(ac);
+ ret = replmd_replicated_apply_isDeleted(ac);
if (ret != LDB_SUCCESS) {
return ldb_module_done(ac->req, NULL, NULL, ret);
}
@@ -2735,8 +2735,11 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
}
/*
- remove links from objects that point at this object when an object
- is deleted
+ * remove links from objects that point at this object when an object
+ * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
+ * RemoveObj which states that link removal due to the object being
+ * deleted is NOT an originating update - they just go away!
+ *
*/
static int replmd_delete_remove_link(struct ldb_module *module,
const struct dsdb_schema *schema,
@@ -2817,8 +2820,13 @@ static int replmd_delete_remove_link(struct ldb_module *module,
This also handles the mapping of delete to a rename operation
to allow deletes to be replicated.
+
+ It also handles the incoming deleted objects, to ensure they are
+ fully deleted here. In that case re_delete is true, and we do not
+ use this as a signal to change the deleted state, just reinforce it.
+
*/
-static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
+static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
{
int ret = LDB_ERR_OTHER;
bool retb, disallow_move_on_delete;
@@ -2861,6 +2869,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
schema = dsdb_get_schema(ldb, tmp_ctx);
if (!schema) {
+ talloc_free(tmp_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -2874,6 +2883,11 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
DSDB_SEARCH_REVEAL_INTERNALS |
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, 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",
+ re_delete ? "re-delete" : "delete",
+ ldb_dn_get_linearized(old_dn),
+ ldb_errstring(ldb_module_get_ctx(module)));
talloc_free(tmp_ctx);
return ret;
}
@@ -2882,8 +2896,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
ret = dsdb_recyclebin_enabled(module, &enabled);
if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
+ enabled = false;
}
if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
@@ -2897,7 +2910,13 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
deletion_state = OBJECT_DELETED;
next_deletion_state = OBJECT_RECYCLED;
}
+
+ /* This supports us noticing an incoming isDeleted and acting on it */
+ if (re_delete) {
+ next_deletion_state = deletion_state;
+ }
} else {
+ SMB_ASSERT(!re_delete);
deletion_state = OBJECT_NOT_DELETED;
if (enabled) {
next_deletion_state = OBJECT_DELETED;
@@ -3006,58 +3025,48 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
*/
- /* 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,
- DSDB_FLAG_NEXT_MODULE |
- DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
- DSDB_SEARCH_REVEAL_INTERNALS|
- DSDB_SEARCH_SHOW_RECYCLED, req);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
- }
-
- if (deletion_state == OBJECT_NOT_DELETED){
- ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
- ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
+ if (deletion_state == OBJECT_NOT_DELETED) {
+ /* 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,
+ DSDB_FLAG_NEXT_MODULE |
+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
+ DSDB_SEARCH_REVEAL_INTERNALS|
+ DSDB_SEARCH_SHOW_RECYCLED, req);
if (ret != LDB_SUCCESS) {
- DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
- ldb_module_oom(module);
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "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_errstring(ldb_module_get_ctx(module)));
talloc_free(tmp_ctx);
return ret;
}
- msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
- }
-
- switch (next_deletion_state){
- case OBJECT_DELETED:
-
- ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
+ 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 msDS-LastKnownRDN string to the msg\n"));
+ DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
ldb_module_oom(module);
talloc_free(tmp_ctx);
return ret;
}
- msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
-
- ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- ldb_module_oom(module);
- return ret;
- }
+ msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
- ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- ldb_module_oom(module);
- return ret;
+ 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);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
}
+ }
- break;
+ switch (next_deletion_state) {
case OBJECT_RECYCLED:
case OBJECT_TOMBSTONE:
@@ -3078,7 +3087,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
talloc_free(tmp_ctx);
return ret;
}
- msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
+ msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
}
/* work out which of the old attributes we will be removing */
@@ -3124,6 +3133,36 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
return ret;
}
}
+
+ /* Duplicate with the below - we remove the
+ * samAccountType as an originating update, in case it
+ * somehow came back. The objectCategory will have
+ * gone in the above */
+ ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ ldb_module_oom(module);
+ return ret;
+ }
+
+ break;
+
+ case OBJECT_DELETED:
+
+ ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ ldb_module_oom(module);
+ return ret;
+ }
+
+ ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ ldb_module_oom(module);
+ return ret;
+ }
+
break;
default:
@@ -3166,6 +3205,11 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
}
}
+ /*
+ * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
+ *
+ */
+
ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
@@ -3192,6 +3236,10 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
}
+static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ return replmd_delete_internals(module, req, false);
+}
static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
@@ -3543,7 +3591,6 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
if (rename_incoming_record) {
struct GUID guid;
struct ldb_dn *new_dn;
- struct ldb_message *new_msg;
/*
* We want to run the original callback here, which
@@ -3580,14 +3627,7 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
/* re-submit the request, but with a different
callback, so we don't loop forever. */
- new_msg = ldb_msg_copy_shallow(req, msg);
- if (!new_msg) {
- goto failed;
- DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
- ldb_dn_get_linearized(conflict_dn)));
- }
- new_msg->dn = new_dn;
- req->op.add.message = new_msg;
+ msg->dn = new_dn;
req->callback = replmd_op_name_modify_callback;
return ldb_next_request(ar->module, req);
@@ -3761,6 +3801,8 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
}
}
+ ar->isDeleted = remote_isDeleted;
+
if (DEBUGLVL(4)) {
char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
DEBUG(4, ("DRS replication add message:\n%s\n", s));
@@ -3907,7 +3949,10 @@ static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
}
/*
- * Look for the parent object, so we put the new object in the right place
+ * Look for the parent object, so we put the new object in the right
+ * place This is akin to NameObject in MS-DRSR - this routine and the
+ * callbacks find the right parent name, and correct name for this
+ * object
*/
static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
@@ -4246,25 +4291,32 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
}
/*
+ * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
+ * UpdateObject.
+ *
+ * This also controls SD propagation below
+ */
+ if (take_remote_isDeleted) {
+ isDeleted = remote_isDeleted;
+ } else {
+ isDeleted = local_isDeleted;
+ }
+
+ ar->isDeleted = isDeleted;
+
+ /*
* check if some replicated attributes left, otherwise skip the ldb_modify() call
*/
if (msg->num_elements == 0) {
ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
ar->index_current);
- ar->index_current++;
- return replmd_replicated_apply_next(ar);
+ return replmd_replicated_apply_isDeleted(ar);
}
ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
ar->index_current, msg->num_elements);
- if (take_remote_isDeleted) {
- isDeleted = remote_isDeleted;
- } else {
- isDeleted = local_isDeleted;
- }
-
if (renamed) {
sd_updated = true;
}
@@ -4470,6 +4522,7 @@ static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
ldb = ldb_module_get_ctx(ar->module);
ar->search_msg = NULL;
+ ar->isDeleted = false;
tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
@@ -4500,6 +4553,81 @@ static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
return ldb_next_request(ar->module, search_req);
}
+/*
+ * This is essentially a wrapper for replmd_replicated_apply_next()
+ *
+ * This is needed to ensure that both codepaths call this handler.
+ */
+static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
+{
+ if (ar->isDeleted) {
+ /*
+ * Do a delete here again, so that if there is
+ * anything local that conflicts with this
+ * object being deleted, it is removed. This
+ * includes links. See MS-DRSR 4.1.10.6.9
+ * UpdateObject.
+ *
+ * If the object is already deleted, and there
+ * is no more work required, it doesn't do
+ * anything.
+ */
+
+ /* This has been updated to point to the DN we eventually did the modify on */
+ struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
+
+ struct ldb_request *del_req;
+ struct ldb_result *res;
+ int ret;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(ar);
+ if (!tmp_ctx) {
+ ret = ldb_oom(ldb_module_get_ctx(ar->module));
+ return ret;
+ }
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ if (!res) {
+ ret = ldb_oom(ldb_module_get_ctx(ar->module));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* Build a delete request, which hopefully will artually turn into nothing */
+ ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
+ msg->dn,
+ NULL,
+ res,
+ ldb_modify_default_callback,
+ ar->req);
+ LDB_REQ_SET_LOCATION(del_req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /*
+ * This is the guts of the call, call bark
+ * into our delete code, but setting the
+ * re_delete flag so we delete anything that
+ * shouldn't be there on a deleted or recycled
+ * object
+ */
+ ret = replmd_delete_internals(ar->module, del_req, true);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
+ }
+
+ talloc_free(tmp_ctx);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ ar->index_current++;
+ return replmd_replicated_apply_next(ar);
+}
+
static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
struct ldb_reply *ares)
{