]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:dsdb/tombstone_reanimate: restructure the module logic
authorStefan Metzmacher <metze@samba.org>
Fri, 8 Jul 2016 12:37:54 +0000 (14:37 +0200)
committerStefan Metzmacher <metze@samba.org>
Sat, 9 Jul 2016 13:06:19 +0000 (15:06 +0200)
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 <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/dsdb/samdb/ldb_modules/tombstone_reanimate.c

index fad856f9bbdbca1baad5bab74c468cf37d60ca47..5a630917ed468676218900702fd0109b387b6d8e 100644 (file)
 #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 ) {