r25723: Add a check to prevent deletion of entries with children. Sadly MMC
authorAndrew Bartlett <abartlet@samba.org>
Thu, 25 Oct 2007 03:04:55 +0000 (05:04 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 21 Dec 2007 04:43:29 +0000 (05:43 +0100)
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

index 8f15f9ed0536c0166a28b703f173c6810553f535..5b0916fdbfbafc88a200fd480e340ac8697eba75 100644 (file)
@@ -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,
 };