provision: Ignore duplicate attid and governsID check
[sfrench/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / subtree_delete.c
index 34914d27b6c46adb03339268e308d5f15f683f12..b1f87f77b544ef99c15fc059c046902ef21e7ddd 100644 (file)
 #include <ldb.h>
 #include <ldb_module.h>
 #include "dsdb/samdb/ldb_modules/util.h"
+#include "dsdb/common/util.h"
 
 
+static int subtree_delete_sort(struct ldb_message **m1,
+                              struct ldb_message **m2,
+                              void *private_data)
+{
+       struct ldb_dn *dn1 = (*m1)->dn;
+       struct ldb_dn *dn2 = (*m2)->dn;
+
+       /*
+        * This sorts in tree order, children first
+        */
+       return ldb_dn_compare(dn1, dn2);
+}
+
 static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
 {
        static const char * const attrs[] = { NULL };
@@ -54,36 +68,58 @@ static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
        ret = dsdb_module_search(module, req, &res, req->op.del.dn,
                                 LDB_SCOPE_ONELEVEL, attrs,
                                 DSDB_FLAG_NEXT_MODULE,
+                                req,
                                 "(objectClass=*)");
        if (ret != LDB_SUCCESS) {
                talloc_free(res);
                return ret;
        }
-       if (res->count > 0) {
-               if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID) == NULL) {
-                       ldb_asprintf_errstring(ldb_module_get_ctx(module),
-                                              "Cannot delete %s, not a leaf node "
-                                              "(has %d children)\n",
-                                              ldb_dn_get_linearized(req->op.del.dn),
-                                              res->count);
-                       talloc_free(res);
-                       return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
-               }
+       if (res->count == 0) {
+               talloc_free(res);
+               return ldb_next_request(module, req);
+       }
 
-               /* we need to start from the top since other LDB modules could
-                * enforce constraints (eg "objectclass" and "samldb" do so). */
-               flags = DSDB_FLAG_TOP_MODULE | DSDB_TREE_DELETE;
-               if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
-                       flags |= DSDB_MODIFY_RELAX;
-               }
+       if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID) == NULL) {
+               /* Do not add any DN outputs to this error string!
+                * Some MMC consoles (eg release 2000) have a strange
+                * bug and prevent subtree deletes afterwards. */
+               ldb_asprintf_errstring(ldb_module_get_ctx(module),
+                                      "subtree_delete: Unable to "
+                                      "delete a non-leaf node "
+                                      "(it has %u children)!",
+                                      res->count);
+               talloc_free(res);
+               return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
+       }
+
+       /*
+        * First we sort the results from the leaf to the root
+        */
+       LDB_TYPESAFE_QSORT(res->msgs, res->count, NULL,
+                          subtree_delete_sort);
+
+       /*
+        * we need to start from the top since other LDB modules could
+        * enforce constraints (eg "objectclass" and "samldb" do so).
+        *
+        * We pass DSDB_FLAG_AS_SYSTEM as the acl module above us
+        * has already checked for SEC_ADS_DELETE_TREE.
+        */
+       flags = DSDB_FLAG_TOP_MODULE |
+               DSDB_FLAG_AS_SYSTEM |
+               DSDB_FLAG_TRUSTED |
+               DSDB_TREE_DELETE;
+       if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
+               flags |= DSDB_MODIFY_RELAX;
+       }
 
-               for (i = 0; i < res->count; i++) {
-                       ret = dsdb_module_del(module, res->msgs[i]->dn, flags);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
+       for (i = 0; i < res->count; i++) {
+               ret = dsdb_module_del(module, res->msgs[i]->dn, flags, req);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
                }
        }
+
        talloc_free(res);
 
        return ldb_next_request(module, req);
@@ -106,8 +142,14 @@ static int subtree_delete_init(struct ldb_module *module)
        return ldb_next_init(module);
 }
 
-_PUBLIC_ const struct ldb_module_ops ldb_subtree_delete_module_ops = {
+static const struct ldb_module_ops ldb_subtree_delete_module_ops = {
        .name              = "subtree_delete",
        .init_context      = subtree_delete_init,
        .del               = subtree_delete
 };
+
+int ldb_subtree_delete_module_init(const char *version)
+{
+       LDB_MODULE_CHECK_VERSION(version);
+       return ldb_register_module(&ldb_subtree_delete_module_ops);
+}