r25942: Make various ldb modules handle an LDB backend that enforces validity
authorAndrew Bartlett <abartlet@samba.org>
Tue, 13 Nov 2007 21:54:52 +0000 (22:54 +0100)
committerStefan Metzmacher <metze@samba.org>
Fri, 21 Dec 2007 04:45:11 +0000 (05:45 +0100)
of Base DNs in searches (returning an error of LDB_ERR_NO_SUCH_ENTRY).

We need to handle this if ldb_tdb is to behave correctly compared with
LDAP, as well as if we are using an LDAP backend.

In doing so, I realised that subtree_rename and subtree_delete
(prevention) need rather different wait loops, so it seemed easier to
split it out into it's own module.

I've fixed the licence on both of these modules to be GPLv3.

Andrew Bartlett
(This used to be commit d3894c90f31fb45e038ab478cd9d7d34962d069b)

source4/dsdb/samdb/ldb_modules/config.mk
source4/dsdb/samdb/ldb_modules/linked_attributes.c
source4/dsdb/samdb/ldb_modules/objectclass.c
source4/dsdb/samdb/ldb_modules/pdc_fsmo.c
source4/dsdb/samdb/ldb_modules/schema_fsmo.c
source4/dsdb/samdb/ldb_modules/subtree_delete.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/subtree_rename.c

index 808fb58048623e1ee0f1502b1172caf314ff0934..3c43d47cef0b09ba93ce8424efef5b65e3961215 100644 (file)
@@ -264,6 +264,19 @@ OBJ_FILES = \
 # End MODULE ldb_subtree_rename
 ################################################
 
+################################################
+# Start MODULE ldb_subtree_rename
+[MODULE::ldb_subtree_delete]
+INIT_FUNCTION = ldb_subtree_delete_init
+OUTPUT_TYPE = SHARED_LIBRARY
+CFLAGS = -Ilib/ldb/include
+PRIVATE_DEPENDENCIES = LIBTALLOC
+SUBSYSTEM = LIBLDB
+OBJ_FILES = \
+               subtree_delete.o
+# End MODULE ldb_subtree_rename
+################################################
+
 ################################################
 # Start MODULE ldb_linked_attributes
 [MODULE::ldb_linked_attributes]
index be5dd12d3b84eda491a448b0270270e654689481..f3e66c5065eb9d55a6c5a55dc759213251ec9bf4 100644 (file)
 #include "dsdb/samdb/samdb.h"
 
 struct linked_attributes_context {
+       enum la_step {LA_SEARCH, LA_DO_OPS} step;
        struct ldb_module *module;
        struct ldb_handle *handle;
        struct ldb_request *orig_req;
 
+       struct ldb_request *search_req;
        struct ldb_request **down_req;
        int num_requests;
        int finished_requests;
@@ -82,7 +84,7 @@ static struct linked_attributes_context *linked_attributes_init_handle(struct ld
 
 static int setup_modifies(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
                          struct linked_attributes_context *ac,
-                         struct ldb_message *msg, 
+                         const struct ldb_message *msg, 
                          struct ldb_dn *olddn, struct ldb_dn *newdn) 
 {
        int i, j, ret = LDB_SUCCESS;
@@ -192,6 +194,7 @@ static int setup_modifies(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
                        ac->down_req[ac->num_requests] = new_req;
                        ac->num_requests++;
                        
+
                        /* Run the new request */
                        ret = ldb_next_request(ac->module, new_req);
                        if (ret != LDB_SUCCESS) {
@@ -272,6 +275,8 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
                
                /* Even link IDs are for the originating attribute */
        }
+
+       ac->step = LA_DO_OPS;
        
        /* Now call the common routine to setup the modifies across all the attributes */
        return setup_modifies(module->ldb, ac, ac, req->op.add.message, NULL, req->op.add.message->dn);
@@ -322,6 +327,8 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
        
        ac->num_requests++;
        
+       ac->step = LA_DO_OPS;
+
        /* Run the original request */
        ret = ldb_next_request(module, ac->down_req[0]);
        if (ret != LDB_SUCCESS) {
@@ -539,18 +546,8 @@ static int linked_attributes_rename(struct ldb_module *module, struct ldb_reques
 
        talloc_steal(new_req, attrs);
 
-       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++;
+       ac->search_req = new_req;
+       ac->step = LA_SEARCH;
        return ldb_next_request(module, new_req);
 }
 
@@ -602,18 +599,8 @@ static int linked_attributes_delete(struct ldb_module *module, struct ldb_reques
 
        talloc_steal(new_req, attrs);
 
-       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++;
+       ac->search_req = new_req;
+       ac->step = LA_SEARCH;
        return ldb_next_request(module, new_req);
 }
 
@@ -634,21 +621,42 @@ static int linked_attributes_wait_none(struct ldb_handle *handle) {
 
        ac = talloc_get_type(handle->private_data, struct linked_attributes_context);
 
-       for (i=0; i < ac->num_requests; i++) {
-               ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
+       switch (ac->step) {
+       case LA_SEARCH:
+               ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
                
                if (ret != LDB_SUCCESS) {
                        handle->status = ret;
                        goto done;
                }
-               if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
-                       handle->status = ac->down_req[i]->handle->status;
+               if (ac->search_req->handle->status != LDB_SUCCESS) {
+                       handle->status = ac->search_req->handle->status;
                        goto done;
                }
                
-               if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
+               if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
                        return LDB_SUCCESS;
                }
+               ac->step = LA_DO_OPS;
+               return LDB_SUCCESS;
+
+       case LA_DO_OPS:
+               for (i=0; i < ac->num_requests; i++) {
+                       ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
+                       
+                       if (ret != LDB_SUCCESS) {
+                               handle->status = ret;
+                               goto done;
+                       }
+                       if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
+                               handle->status = ac->down_req[i]->handle->status;
+                               goto done;
+                       }
+                       
+                       if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
+                               return LDB_SUCCESS;
+                       }
+               }
        }
 
 done:
index 50ea2ec4e2346886dcd2134d630dcebaf844beae..5626d9a891d76e0e3d14af5c35182f653060493b 100644 (file)
@@ -68,6 +68,8 @@ struct class_list {
        const struct dsdb_class *objectclass;
 };
 
+static int objectclass_do_add(struct ldb_handle *h);
+
 static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
 {
        struct oc_context *ac;
@@ -388,11 +390,17 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
        /* return or own handle to deal with this call */
        req->handle = h;
 
-       parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.mod.message->dn);
+       /* If there isn't a parent, just go on to the add processing */
+       if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) == 1) {
+               return objectclass_do_add(h);
+       }
+
+       parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.add.message->dn);
        if (parent_dn == NULL) {
                ldb_oom(module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
+
        ret = ldb_build_search_req(&ac->search_req, module->ldb,
                                   ac, parent_dn, LDB_SCOPE_BASE,
                                   "(objectClass=*)",
@@ -443,9 +451,7 @@ static int objectclass_do_add(struct ldb_handle *h)
        
        /* Check we have a valid parent */
        if (ac->search_res == NULL) {
-               if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) <= 1) {
-                       /* Allow cn=rootdse and cn=templates for now... */
-               } else if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) {
+               if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) {
                        /* Allow the tree to be started */
                } else {
                        ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!", 
@@ -461,6 +467,8 @@ static int objectclass_do_add(struct ldb_handle *h)
                             &msg->dn);
 
                if (ret != LDB_SUCCESS) {
+                       ldb_asprintf_errstring(ac->module->ldb, "Could not munge DN %s into normal form", 
+                                              ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
                        return ret;
                }
 
@@ -601,7 +609,9 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
 
        switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
        case LDB_FLAG_MOD_DELETE:
-               return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
+               if (objectclass_element->num_values == 0) {
+                       return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
+               }
                break;
        case LDB_FLAG_MOD_REPLACE:
        {
@@ -1026,11 +1036,12 @@ static int oc_wait(struct ldb_handle *handle) {
        case OC_SEARCH_ADD_PARENT:
                ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
 
-               if (ret != LDB_SUCCESS) {
+               if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ret;
                        goto done;
                }
-               if (ac->search_req->handle->status != LDB_SUCCESS) {
+               if (ac->search_req->handle->status != LDB_SUCCESS
+                   && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ac->search_req->handle->status;
                        goto done;
                }
@@ -1063,11 +1074,11 @@ static int oc_wait(struct ldb_handle *handle) {
        case OC_SEARCH_RENAME_PARENT:
                ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
 
-               if (ret != LDB_SUCCESS) {
+               if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ret;
                        goto done;
                }
-               if (ac->search_req->handle->status != LDB_SUCCESS) {
+               if (ac->search_req->handle->status != LDB_SUCCESS && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ac->search_req->handle->status;
                        goto done;
                }
index d78ba14ab46f14a4d3f8264a59fbde5174096d6f..ed9b554bb19e1067c7659f89fd33e9f4a823c2b2 100644 (file)
@@ -67,7 +67,12 @@ static int pdc_fsmo_init(struct ldb_module *module)
                         LDB_SCOPE_BASE,
                         NULL, pdc_attrs,
                         &pdc_res);
-       if (ret != LDB_SUCCESS) {
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+                         "pdc_fsmo_init: no domain object present: (skip loading of domain details)");
+               talloc_free(mem_ctx);
+               return ldb_next_init(module);
+       } else if (ret != LDB_SUCCESS) {
                ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
                              "pdc_fsmo_init: failed to search the domain object: %d:%s",
                              ret, ldb_strerror(ret));
index a92f2646c4196c48dc19e1cf06efa68733a13ed7..b10e3ac203ce9759d667a36ae0b1be775daaf2f2 100644 (file)
@@ -90,7 +90,12 @@ static int schema_fsmo_init(struct ldb_module *module)
                         LDB_SCOPE_BASE,
                         NULL, schema_attrs,
                         &schema_res);
-       if (ret != LDB_SUCCESS) {
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+                         "schema_fsmo_init: no schema head present: (skip schema loading)");
+               talloc_free(mem_ctx);
+               return ldb_next_init(module);
+       } else if (ret != LDB_SUCCESS) {
                ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
                              "schema_fsmo_init: failed to search the schema head: %d:%s",
                              ret, ldb_strerror(ret));
diff --git a/source4/dsdb/samdb/ldb_modules/subtree_delete.c b/source4/dsdb/samdb/ldb_modules/subtree_delete.c
new file mode 100644 (file)
index 0000000..92f5394
--- /dev/null
@@ -0,0 +1,255 @@
+/* 
+   ldb database library
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2007
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb subtree delete (prevention) module
+ *
+ *  Description: Prevent deletion of a subtree in LDB
+ *
+ *  Author: Andrew Bartlett
+ */
+
+#include "ldb_includes.h"
+
+struct subtree_delete_context {
+       enum sd_step {SD_SEARCH, SD_DO_DEL} step;
+
+       struct ldb_module *module;
+       struct ldb_handle *handle;
+       struct ldb_request *orig_req;
+
+       struct ldb_request *search_req;
+       struct ldb_request *down_req;
+
+       int num_children;
+};
+
+static struct subtree_delete_context *subtree_delete_init_handle(struct ldb_request *req, 
+                                                                struct ldb_module *module)
+{
+       struct subtree_delete_context *ac;
+       struct ldb_handle *h;
+
+       h = talloc_zero(req, struct ldb_handle);
+       if (h == NULL) {
+               ldb_set_errstring(module->ldb, "Out of Memory");
+               return NULL;
+       }
+
+       h->module = module;
+
+       ac = talloc_zero(h, struct subtree_delete_context);
+       if (ac == NULL) {
+               ldb_set_errstring(module->ldb, "Out of Memory");
+               talloc_free(h);
+               return NULL;
+       }
+
+       h->private_data = ac;
+
+       ac->module = module;
+       ac->handle = h;
+       ac->orig_req = req;
+
+       req->handle = h;
+
+       return ac;
+}
+
+static int subtree_delete_check_for_children(struct subtree_delete_context *ac)
+{
+       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 {
+               struct ldb_request *req = talloc(ac, struct ldb_request);
+               if (!req) {
+                       ldb_oom(ac->module->ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               *req = *ac->orig_req;
+               
+               ac->down_req = req;
+               ac->step = SD_DO_DEL;
+               return ldb_next_request(ac->module, req);
+       }
+}
+
+static int subtree_delete_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) 
+{
+       struct subtree_delete_context *ac = talloc_get_type(context, struct subtree_delete_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;
+}
+
+/* rename */
+static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
+{
+       const char *attrs[] = { NULL };
+       struct ldb_request *new_req;
+       struct subtree_delete_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, count the children (if any)
+          - return an error if there are any
+       */
+
+       ac = subtree_delete_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->search_req = new_req;
+       if (req == NULL) {
+               ldb_oom(ac->module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       return ldb_next_request(module, new_req);
+}
+
+
+static int subtree_delete_wait_none(struct ldb_handle *handle) {
+       struct subtree_delete_context *ac;
+       int ret = LDB_ERR_OPERATIONS_ERROR;
+       if (!handle || !handle->private_data) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       if (handle->state == LDB_ASYNC_DONE) {
+               return handle->status;
+       }
+
+       handle->state = LDB_ASYNC_PENDING;
+       handle->status = LDB_SUCCESS;
+
+       ac = talloc_get_type(handle->private_data, struct subtree_delete_context);
+
+       switch (ac->step) {
+       case SD_SEARCH:
+               ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
+
+               if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
+                       handle->status = ret;
+                       goto done;
+               }
+               if (ac->search_req->handle->status != LDB_SUCCESS
+                       && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
+                       handle->status = ac->search_req->handle->status;
+                       goto done;
+               }
+
+               return subtree_delete_check_for_children(ac);
+
+       case SD_DO_DEL:
+               ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
+
+               if (ret != LDB_SUCCESS) {
+                       handle->status = ret;
+                       goto done;
+               }
+               if (ac->down_req->handle->status != LDB_SUCCESS) {
+                       handle->status = ac->down_req->handle->status;
+                       goto done;
+               }
+
+               if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
+                       return LDB_SUCCESS;
+               }
+
+               break;
+       }
+done:
+       handle->state = LDB_ASYNC_DONE;
+       return ret;
+}
+
+static int subtree_delete_wait_all(struct ldb_handle *handle) {
+
+       int ret;
+
+       while (handle->state != LDB_ASYNC_DONE) {
+               ret = subtree_delete_wait_none(handle);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       return handle->status;
+}
+
+static int subtree_delete_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+       if (type == LDB_WAIT_ALL) {
+               return subtree_delete_wait_all(handle);
+       } else {
+               return subtree_delete_wait_none(handle);
+       }
+}
+
+static const struct ldb_module_ops subtree_delete_ops = {
+       .name              = "subtree_delete",
+       .del               = subtree_delete,
+       .wait              = subtree_delete_wait,
+};
+
+int ldb_subtree_delete_init(void)
+{
+       return ldb_register_module(&subtree_delete_ops);
+}
index 72857cb864e7c5bc63f48a9b593781bd36aeec7c..0964c3fdcd6567bb3ff2112367488c2bdb338944 100644 (file)
@@ -4,22 +4,18 @@
    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2007
    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
 
-     ** NOTE! The following LGPL license applies to the ldb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
    
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
@@ -206,113 +202,6 @@ static int subtree_rename(struct ldb_module *module, struct ldb_request *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;
@@ -378,7 +267,6 @@ 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,
 };