summaryrefslogtreecommitdiff
path: root/source4/dsdb/samdb
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2007-10-25 05:04:55 +0200
committerStefan Metzmacher <metze@samba.org>2007-12-21 05:43:29 +0100
commit1f680ef45d8ff95aca2834cd9005f03409019efd (patch)
tree309ac49742a3694cde58e252cb377af158e80737 /source4/dsdb/samdb
parentb28810ab9469be0c445123149931386867c9e6b8 (diff)
downloadsamba-1f680ef45d8ff95aca2834cd9005f03409019efd.tar.gz
samba-1f680ef45d8ff95aca2834cd9005f03409019efd.tar.bz2
samba-1f680ef45d8ff95aca2834cd9005f03409019efd.zip
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)
Diffstat (limited to 'source4/dsdb/samdb')
-rw-r--r--source4/dsdb/samdb/ldb_modules/subtree_rename.c113
1 files changed, 112 insertions, 1 deletions
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,
};