From 1f680ef45d8ff95aca2834cd9005f03409019efd Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 25 Oct 2007 05:04:55 +0200 Subject: r25723: Add a check to prevent deletion of entries with children. Sadly MMC doesn't trigger it's recursive delete correctly, but the error return is correct (but perhaps needs a different LDAP wire format). Andrew Bartlett (This used to be commit 10ba3ae6990098e772683de9144b13b3f1d45a36) --- source4/dsdb/samdb/ldb_modules/subtree_rename.c | 113 +++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) (limited to 'source4/dsdb/samdb/ldb_modules/subtree_rename.c') diff --git a/source4/dsdb/samdb/ldb_modules/subtree_rename.c b/source4/dsdb/samdb/ldb_modules/subtree_rename.c index 8f15f9ed05..5b0916fdbf 100644 --- a/source4/dsdb/samdb/ldb_modules/subtree_rename.c +++ b/source4/dsdb/samdb/ldb_modules/subtree_rename.c @@ -42,6 +42,8 @@ struct subtree_rename_context { struct ldb_request **down_req; int num_requests; int finished_requests; + + int num_children; }; static struct subtree_rename_context *subtree_rename_init_handle(struct ldb_request *req, @@ -95,7 +97,7 @@ static int subtree_rename_search_callback(struct ldb_context *ldb, void *context /* Only entries are interesting, and we handle the case of the parent seperatly */ if (ares->type == LDB_REPLY_ENTRY - && ldb_dn_compare(ares->message->dn, ac->orig_req->op.rename.olddn) != 0) { + && ldb_dn_compare(ares->message->dn, ac->orig_req->op.rename.olddn) == 0) { /* And it is an actual entry: now create a rename from it */ int ret; @@ -203,6 +205,114 @@ static int subtree_rename(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, new_req); } + +static int subtree_delete_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct ldb_request *req; + struct subtree_rename_context *ac = talloc_get_type(context, struct subtree_rename_context); + TALLOC_CTX *mem_ctx = talloc_new(ac); + + if (!mem_ctx) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + /* OK, we have one of *many* search results here: + + We should also get the entry we tried to rename. This + callback handles this and everything below it. + */ + + /* Only entries are interesting, and we handle the case of the parent seperatly */ + if (ares->type == LDB_REPLY_ENTRY + && ldb_dn_compare(ares->message->dn, ac->orig_req->op.del.dn) != 0) { + /* And it is an actual entry: now object bitterly that we are not a leaf node */ + ac->num_children++; + talloc_free(ares); + return LDB_SUCCESS; + } else if (ares->type == LDB_REPLY_DONE) { + talloc_free(ares); + if (ac->num_children > 0) { + ldb_asprintf_errstring(ac->module->ldb, "Cannot delete %s, not a leaf node (has %d children)\n", + ldb_dn_get_linearized(ac->orig_req->op.del.dn), ac->num_children); + return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF; + } else { + req = talloc(mem_ctx, struct ldb_request); + if (!req) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + *req = *ac->orig_req; + + ac->down_req = talloc_realloc(ac, ac->down_req, + struct ldb_request *, ac->num_requests + 1); + if (!ac->down_req) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->down_req[ac->num_requests] = req; + ac->num_requests++; + + return ldb_next_request(ac->module, req); + } + } else { + talloc_free(ares); + return LDB_SUCCESS; + } +} + +/* rename */ +static int subtree_delete(struct ldb_module *module, struct ldb_request *req) +{ + const char *attrs[] = { NULL }; + struct ldb_request *new_req; + struct subtree_rename_context *ac; + int ret; + if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */ + return ldb_next_request(module, req); + } + + /* This gets complex: We need to: + - Do a search for all entires under this entry + - Wait for these results to appear + - In the callback for each result, issue a modify request + - That will include this rename, we hope + - Wait for each modify result + - Regain our sainity + */ + + ac = subtree_rename_init_handle(req, module); + if (!ac) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&new_req, module->ldb, req, + req->op.del.dn, + LDB_SCOPE_SUBTREE, + "(objectClass=*)", + attrs, + req->controls, + ac, + subtree_delete_search_callback); + + if (ret != LDB_SUCCESS) { + return ret; + } + + ac->down_req = talloc_realloc(ac, ac->down_req, + struct ldb_request *, ac->num_requests + 1); + if (!ac->down_req) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->down_req[ac->num_requests] = new_req; + if (req == NULL) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->num_requests++; + return ldb_next_request(module, new_req); +} + static int subtree_rename_wait_none(struct ldb_handle *handle) { struct subtree_rename_context *ac; int i, ret = LDB_ERR_OPERATIONS_ERROR; @@ -268,6 +378,7 @@ static int subtree_rename_wait(struct ldb_handle *handle, enum ldb_wait_type typ static const struct ldb_module_ops subtree_rename_ops = { .name = "subtree_rename", .rename = subtree_rename, + .del = subtree_delete, .wait = subtree_rename_wait, }; -- cgit