#include "libds/common/flag_mapping.h"
struct tr_context {
-
struct ldb_module *module;
+
struct ldb_request *req;
- const struct dsdb_schema *schema;
+ const struct ldb_message *req_msg;
- struct ldb_reply *search_res;
- struct ldb_reply *search_res2;
+ struct ldb_result *search_res;
+ const struct ldb_message *search_msg;
- int (*step_fn)(struct tr_context *);
+ struct ldb_message *mod_msg;
+ struct ldb_result *mod_res;
+ struct ldb_request *mod_req;
+
+ struct ldb_dn *rename_dn;
+ struct ldb_result *rename_res;
+ struct ldb_request *rename_req;
+
+ const struct dsdb_schema *schema;
};
static struct tr_context *tr_init_context(struct ldb_module *module,
struct ldb_request *req)
{
- struct ldb_context *ldb;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
struct tr_context *ac;
- ldb = ldb_module_get_ctx(module);
-
ac = talloc_zero(req, struct tr_context);
if (ac == NULL) {
ldb_oom(ldb);
ac->module = module;
ac->req = req;
+ ac->req_msg = req->op.mod.message;
ac->schema = dsdb_get_schema(ldb, ac);
return ac;
}
-static bool is_tombstone_reanimate_request(struct ldb_request *req, struct ldb_message_element **pel_dn)
+static bool is_tombstone_reanimate_request(struct ldb_request *req,
+ const struct ldb_message_element **pel_dn)
{
struct ldb_message_element *el_dn;
struct ldb_message_element *el_deleted;
/* check distinguishedName requirement */
el_dn = ldb_msg_find_element(req->op.mod.message, "distinguishedName");
- if (el_dn == NULL || el_dn->flags != LDB_FLAG_MOD_REPLACE) {
+ if (el_dn == NULL) {
+ return false;
+ }
+ if (el_dn->flags != LDB_FLAG_MOD_REPLACE) {
+ return false;
+ }
+ if (el_dn->num_values != 1) {
return false;
}
/* check isDeleted requirement */
el_deleted = ldb_msg_find_element(req->op.mod.message, "isDeleted");
- if (el_deleted == NULL || el_deleted->flags != LDB_FLAG_MOD_DELETE) {
+ if (el_deleted == NULL) {
+ return false;
+ }
+
+ if (el_deleted->flags != LDB_FLAG_MOD_DELETE) {
return false;
}
* Local rename implementation based on dsdb_module_rename()
* so we could fine tune it and add more controls
*/
-static int tr_do_rename(struct ldb_module *module, struct ldb_request *parent_req,
- struct ldb_dn *dn_from, struct ldb_dn *dn_to)
+static int tr_prepare_rename(struct tr_context *ac,
+ const struct ldb_message_element *new_dn)
{
- int ret;
- struct ldb_request *req;
- struct ldb_context *ldb = ldb_module_get_ctx(module);
- TALLOC_CTX *tmp_ctx = talloc_new(parent_req);
- 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(module));
- }
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ int ret;
- ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
- dn_from,
- dn_to,
- NULL,
- res,
- ldb_modify_default_callback,
- parent_req);
- LDB_REQ_SET_LOCATION(req);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
+ ac->rename_dn = ldb_dn_from_ldb_val(ac, ldb, &new_dn->values[0]);
+ if (ac->rename_dn == NULL) {
+ return ldb_module_oom(ac->module);
}
- ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
+ ac->rename_res = talloc_zero(ac, struct ldb_result);
+ if (ac->rename_res == NULL) {
+ return ldb_module_oom(ac->module);
}
- /* mark request as part of Tombstone reanimation */
- ret = ldb_request_add_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID, false, NULL);
+ ret = ldb_build_rename_req(&ac->rename_req, ldb, ac,
+ ac->req_msg->dn,
+ ac->rename_dn,
+ NULL,
+ ac->rename_res,
+ ldb_modify_default_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(ac->rename_req);
if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
return ret;
}
- /*
- * Run request from the top module
- * so we get show_deleted control OID resolved
- */
- ret = ldb_next_request(module, req);
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
-
- talloc_free(tmp_ctx);
return ret;
}
* Local rename implementation based on dsdb_module_modify()
* so we could fine tune it and add more controls
*/
-static int tr_do_modify(struct ldb_module *module, struct ldb_request *parent_req, struct ldb_message *msg)
+static int tr_do_down_req(struct tr_context *ac, struct ldb_request *down_req)
{
- int ret;
- struct ldb_request *mod_req;
- struct ldb_context *ldb = ldb_module_get_ctx(module);
- TALLOC_CTX *tmp_ctx = talloc_new(parent_req);
- 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(module));
- }
-
- ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
- msg,
- NULL,
- res,
- ldb_modify_default_callback,
- parent_req);
- LDB_REQ_SET_LOCATION(mod_req);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
- }
+ int ret;
/* We need this since object is 'delete' atm */
- ret = ldb_request_add_control(mod_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
+ ret = ldb_request_add_control(down_req,
+ LDB_CONTROL_SHOW_DELETED_OID,
+ false, NULL);
if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
return ret;
}
/* mark request as part of Tombstone reanimation */
- ret = ldb_request_add_control(mod_req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID, false, NULL);
+ ret = ldb_request_add_control(down_req,
+ DSDB_CONTROL_RESTORE_TOMBSTONE_OID,
+ false, NULL);
if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
return ret;
}
/* Run request from Next module */
- ret = ldb_next_request(module, mod_req);
+ ret = ldb_next_request(ac->module, down_req);
if (ret == LDB_SUCCESS) {
- ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
+ ret = ldb_wait(down_req->handle, LDB_WAIT_ALL);
}
- talloc_free(tmp_ctx);
return ret;
}
-static int tr_restore_attributes(struct ldb_context *ldb, struct ldb_message *cur_msg, struct ldb_message *new_msg)
+static int tr_prepare_attributes(struct tr_context *ac)
{
- int ret;
- struct ldb_message_element *el;
- uint32_t account_type, user_account_control;
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ int ret;
+ struct ldb_message_element *el = NULL;
+ uint32_t account_type, user_account_control;
+ struct ldb_dn *objectcategory = NULL;
+
+ ac->mod_msg = ldb_msg_copy_shallow(ac, ac->req_msg);
+ if (ac->mod_msg == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ ac->mod_res = talloc_zero(ac, struct ldb_result);
+ if (ac->mod_res == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ ret = ldb_build_mod_req(&ac->mod_req, ldb, ac,
+ ac->mod_msg,
+ NULL,
+ ac->mod_res,
+ ldb_modify_default_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(ac->mod_req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ /* - remove distinguishedName - we don't need it */
+ ldb_msg_remove_attr(ac->mod_msg, "distinguishedName");
/* remove isRecycled */
- ret = ldb_msg_add_empty(new_msg, "isRecycled", LDB_FLAG_MOD_DELETE, NULL);
+ ret = ldb_msg_add_empty(ac->mod_msg, "isRecycled",
+ LDB_FLAG_MOD_DELETE, NULL);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ldb, "Failed to reset isRecycled attribute: %s", ldb_strerror(ret));
return LDB_ERR_OPERATIONS_ERROR;
}
/* objectClass is USER */
- if (samdb_find_attribute(ldb, cur_msg, "objectclass", "user") != NULL) {
+ if (samdb_find_attribute(ldb, ac->search_msg, "objectclass", "user") != NULL) {
uint32_t primary_group_rid;
/* restoring 'user' instance attribute is heavily borrowed from samldb.c */
/* Default values */
- ret = dsdb_user_obj_set_defaults(ldb, new_msg, NULL);
- if (ret != LDB_SUCCESS) return ret;
-
- /* Following are set only while reanimating objects */
- ret = samdb_find_or_add_attribute(ldb, new_msg,
- "adminCount", "0");
- if (ret != LDB_SUCCESS) return ret;
- ret = samdb_find_or_add_attribute(ldb, new_msg,
- "operatorCount", "0");
+ ret = dsdb_user_obj_set_defaults(ldb, ac->mod_msg, ac->mod_req);
if (ret != LDB_SUCCESS) return ret;
/* "userAccountControl" must exists on deleted object */
- user_account_control = ldb_msg_find_attr_as_uint(cur_msg, "userAccountControl", (uint32_t)-1);
+ user_account_control = ldb_msg_find_attr_as_uint(ac->search_msg,
+ "userAccountControl",
+ (uint32_t)-1);
if (user_account_control == (uint32_t)-1) {
return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
"reanimate: No 'userAccountControl' attribute found!");
}
/* restore "sAMAccountType" */
- ret = dsdb_user_obj_set_account_type(ldb, new_msg, user_account_control, NULL);
+ ret = dsdb_user_obj_set_account_type(ldb, ac->mod_msg,
+ user_account_control, NULL);
if (ret != LDB_SUCCESS) {
return ret;
}
/* "userAccountControl" -> "primaryGroupID" mapping */
- ret = dsdb_user_obj_set_primary_group_id(ldb, new_msg, user_account_control, &primary_group_rid);
+ ret = dsdb_user_obj_set_primary_group_id(ldb, ac->mod_msg,
+ user_account_control,
+ &primary_group_rid);
if (ret != LDB_SUCCESS) {
return ret;
}
}
/* objectClass is GROUP */
- if (samdb_find_attribute(ldb, cur_msg, "objectclass", "group") != NULL) {
+ if (samdb_find_attribute(ldb, ac->search_msg, "objectclass", "group") != NULL) {
/* "groupType" -> "sAMAccountType" */
uint32_t group_type;
- el = ldb_msg_find_element(cur_msg, "groupType");
+ el = ldb_msg_find_element(ac->search_msg, "groupType");
if (el == NULL) {
return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
"reanimate: Unexpected: missing groupType attribute.");
}
- group_type = ldb_msg_find_attr_as_uint(cur_msg,
+ group_type = ldb_msg_find_attr_as_uint(ac->search_msg,
"groupType", 0);
account_type = ds_gtype2atype(group_type);
return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
"reanimate: Unrecognized account type!");
}
- ret = samdb_msg_add_uint(ldb, new_msg, new_msg,
+ ret = samdb_msg_add_uint(ldb, ac->mod_msg, ac->mod_msg,
"sAMAccountType", account_type);
if (ret != LDB_SUCCESS) {
return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
"reanimate: Failed to add sAMAccountType to restored object.");
}
- el = ldb_msg_find_element(new_msg, "sAMAccountType");
+ el = ldb_msg_find_element(ac->mod_msg, "sAMAccountType");
el->flags = LDB_FLAG_MOD_REPLACE;
/* Default values set by Windows */
- ret = samdb_find_or_add_attribute(ldb, new_msg,
+ ret = samdb_find_or_add_attribute(ldb, ac->mod_msg,
"adminCount", "0");
if (ret != LDB_SUCCESS) return ret;
- ret = samdb_find_or_add_attribute(ldb, new_msg,
+ ret = samdb_find_or_add_attribute(ldb, ac->mod_msg,
"operatorCount", "0");
if (ret != LDB_SUCCESS) return ret;
}
+ /* - restore objectCategory if not present */
+ objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_msg,
+ "objectCategory");
+ if (objectcategory == NULL) {
+ const char *value;
+
+ ret = dsdb_make_object_category(ldb, ac->schema, ac->search_msg,
+ ac->mod_msg, &value);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_msg_add_string(ac->mod_msg, "objectCategory", value);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ el = ldb_msg_find_element(ac->mod_msg, "objectCategory");
+ el->flags = LDB_FLAG_MOD_ADD;
+ }
+
return LDB_SUCCESS;
}
*/
static int tombstone_reanimate_modify(struct ldb_module *module, struct ldb_request *req)
{
- int ret;
- struct ldb_context *ldb;
- struct ldb_dn *dn_new;
- struct ldb_dn *objectcategory;
- struct ldb_message_element *el_dn = NULL;
- struct ldb_message *msg;
- struct ldb_result *res_obj;
- struct tr_context *ac;
-
- ldb = ldb_module_get_ctx(module);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ const struct ldb_message_element *el_dn = NULL;
+ struct tr_context *ac = NULL;
+ int ret;
ldb_debug(ldb, LDB_DEBUG_TRACE, "%s\n", __PRETTY_FUNCTION__);
}
/* Load original object */
- ret = dsdb_module_search_dn(module, req, &res_obj, req->op.mod.message->dn, NULL, DSDB_FLAG_TOP_MODULE | DSDB_SEARCH_SHOW_DELETED, req);
+ ret = dsdb_module_search_dn(module, ac, &ac->search_res,
+ ac->req_msg->dn, NULL,
+ DSDB_FLAG_TOP_MODULE |
+ DSDB_SEARCH_SHOW_DELETED,
+ req);
if (ret != LDB_SUCCESS) {
return ldb_operr(ldb);
}
+ ac->search_msg = ac->search_res->msgs[0];
+
/* check if it a Deleted Object */
- if (!ldb_msg_find_attr_as_bool(res_obj->msgs[0], "isDeleted", false)) {
+ if (!ldb_msg_find_attr_as_bool(ac->search_msg, "isDeleted", false)) {
return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM, "Trying to restore not deleted object\n");
}
/* Simple implementation */
- /* Modify request to: */
- msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
- if (msg == NULL) {
- return ldb_module_oom(ac->module);
+ /* prepare attributed depending on objectClass */
+ ret = tr_prepare_attributes(ac);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- /* - remove distinguishedName - we don't need it */
- ldb_msg_remove_attr(msg, "distinguishedName");
- /* restore attributed depending on objectClass */
- ret = tr_restore_attributes(ldb, res_obj->msgs[0], msg);
+ /* Rename request to modify distinguishedName */
+ ret = tr_prepare_rename(ac, el_dn);
if (ret != LDB_SUCCESS) {
return ret;
}
- /* - restore objectCategory if not present */
- objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
- "objectCategory");
- if (objectcategory == NULL) {
- const char *value;
-
- ret = dsdb_make_object_category(ldb, ac->schema, res_obj->msgs[0], msg, &value);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_msg_add_string(msg, "objectCategory", value);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- msg->elements[msg->num_elements-1].flags = LDB_FLAG_MOD_ADD;
- }
- ret = tr_do_modify(module, req, msg);
+ /* restore attributed depending on objectClass */
+ ret = tr_do_down_req(ac, ac->mod_req);
if (ret != LDB_SUCCESS) {
return ret;
}
/* Rename request to modify distinguishedName */
- dn_new = ldb_dn_from_ldb_val(req, ldb, &el_dn->values[0]);
- if (dn_new == NULL) {
- return ldb_oom(ldb);
- }
- ret = tr_do_rename(module, req, req->op.mod.message->dn, dn_new);
+ ret = tr_do_down_req(ac, ac->rename_req);
if (ret != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Renaming object to %s has failed with %s\n", el_dn->values[0].data, ldb_strerror(ret));
if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS && ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ) {