From c16b30c4113a2d6598d98e8353435e204951094c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Jul 2016 14:37:54 +0200 Subject: [PATCH] s4:dsdb/tombstone_reanimate: restructure the module logic Now we keep all state in struct tr_context and split the preparation and exectution of sub requests into helper functions. The most important change is that we now pass mod_req to dsdb_user_obj_set_defaults(), so that it can add controls to it. Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- .../samdb/ldb_modules/tombstone_reanimate.c | 297 +++++++++--------- 1 file changed, 146 insertions(+), 151 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c b/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c index fad856f9bbd..5a630917ed4 100644 --- a/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c +++ b/source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c @@ -53,25 +53,31 @@ #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); @@ -80,26 +86,38 @@ static struct tr_context *tr_init_context(struct ldb_module *module, 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; } @@ -111,57 +129,34 @@ static bool is_tombstone_reanimate_request(struct ldb_request *req, struct ldb_m * 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; } @@ -169,102 +164,104 @@ static int tr_do_rename(struct ldb_module *module, struct ldb_request *parent_re * 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; } @@ -279,17 +276,17 @@ static int tr_restore_attributes(struct ldb_context *ldb, struct ldb_message *cu } /* 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); @@ -297,24 +294,44 @@ static int tr_restore_attributes(struct ldb_context *ldb, struct ldb_message *cu 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; } @@ -323,16 +340,10 @@ static int tr_restore_attributes(struct ldb_context *ldb, struct ldb_message *cu */ 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__); @@ -352,59 +363,43 @@ static int tombstone_reanimate_modify(struct ldb_module *module, struct ldb_requ } /* 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 ) { -- 2.47.3