s4-dsdb: it is a better pattern to mark a control as done than remove it
[samba.git] / source4 / dsdb / samdb / ldb_modules / show_deleted.c
index 361cf226dc331b1a8a46059213c512552983fb81..666d28053c236fbfd35711c8e25bef61c9b73d65 100644 (file)
@@ -2,24 +2,21 @@
    ldb database library
 
    Copyright (C) Simo Sorce  2005
-   Copyright (C) Stefa Metzmacher <metze@samba.org> 2007
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
 
-     ** 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/>.
 */
 
 /*
  *
  *  Component: ldb deleted objects control module
  *
- *  Description: this module hides deleted objects, and returns them if the control is there
+ *  Description: this module hides deleted objects, and returns them if the right control is there
  *
  *  Author: Stefan Metzmacher
  */
 
 #include "includes.h"
-#include "ldb/include/ldb.h"
-#include "ldb/include/ldb_errors.h"
-#include "ldb/include/ldb_private.h"
+#include "ldb/include/ldb_module.h"
 #include "dsdb/samdb/samdb.h"
 
-/* search */
-struct show_deleted_search_request {
-
-       struct ldb_module *module;
-       void *up_context;
-       int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
-
-       bool remove_from_msg;
-};
-
-static int show_deleted_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
-       struct show_deleted_search_request *ar;
-
-       ar = talloc_get_type(context, struct show_deleted_search_request);
-
-       if (ares->type == LDB_REPLY_ENTRY) {
-               bool isDeleted;
-
-               isDeleted = ldb_msg_find_attr_as_bool(ares->message, "isDeleted", false);
-
-               if (isDeleted) {
-                       goto skip_deleted;
-               }
-
-               if (ar->remove_from_msg) {
-                       ldb_msg_remove_attr(ares->message, "isDeleted");
-               }
-       }
-
-       return ar->up_callback(ldb, ar->up_context, ares);
-
-skip_deleted:
-       talloc_free(ares);
-       return LDB_SUCCESS;
-}
 
 static int show_deleted_search(struct ldb_module *module, struct ldb_request *req)
 {
+       struct ldb_context *ldb;
        struct ldb_control *control;
-       struct ldb_control **saved_controls;
-       struct show_deleted_search_request *ar;
        struct ldb_request *down_req;
-       char **new_attrs;
-       uint32_t num_attrs = 0;
-       uint32_t i;
+       struct ldb_parse_tree *new_tree = req->op.search.tree;
        int ret;
 
+       ldb = ldb_module_get_ctx(module);
+
        /* check if there's a show deleted control */
        control = ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID);
 
-       /* copy the request for modification */
-       down_req = talloc(req, struct ldb_request);
-       if (down_req == NULL) {
-               ldb_oom(module->ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       /* copy the request */
-       *down_req = *req;
-
-       /* if a control is there remove if from the modified request */
-       if (control && !save_controls(control, down_req, &saved_controls)) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       /* if we had a control, then just go on to the next request as we have nothing to hide */
-       if (control) {
-               goto next_request;
-       }
-
-       ar = talloc(down_req, struct show_deleted_search_request);
-       if (ar == NULL) {
-               ldb_oom(module->ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ar->module              = module;
-       ar->up_context          = req->context;
-       ar->up_callback         = req->callback;
-       ar->remove_from_msg     = true;
-
-       /* check if attrs only is specified, in that case check wether we need to modify them */
-       if (down_req->op.search.attrs) {
-               for (i=0; (down_req->op.search.attrs && down_req->op.search.attrs[i]); i++) {
-                       num_attrs++;
-                       if (strcasecmp(down_req->op.search.attrs[i], "*") == 0) {
-                               ar->remove_from_msg = false;
-                       } else if (strcasecmp(down_req->op.search.attrs[i], "isDeleted") == 0) {
-                               ar->remove_from_msg = false;
-                       }
-               }
-       } else {
-               ar->remove_from_msg = false;
-       }
-
-       if (ar->remove_from_msg) {
-               new_attrs = talloc_array(down_req, char *, num_attrs + 2);
-               if (!new_attrs) {
-                       ldb_oom(module->ldb);
+       if (! control) {
+               /* FIXME: we could use a constant tree here once we
+                  are sure that no ldb modules modify trees
+                  in-situ */
+               new_tree = talloc(req, struct ldb_parse_tree);
+               if (!new_tree) {
+                       ldb_oom(ldb);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
-               for (i=0; i < num_attrs; i++) {
-                       new_attrs[i] = discard_const_p(char, down_req->op.search.attrs[i]);             
+               new_tree->operation = LDB_OP_AND;
+               new_tree->u.list.num_elements = 2;
+               new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, 2);
+               if (!new_tree->u.list.elements) {
+                       ldb_oom(ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
                }
-               new_attrs[i] = talloc_strdup(new_attrs, "isDeleted");
-               if (!new_attrs[i]) {
-                       ldb_oom(module->ldb);
+               new_tree->u.list.elements[0] = talloc(new_tree->u.list.elements, struct ldb_parse_tree);
+               new_tree->u.list.elements[0]->operation = LDB_OP_NOT;
+               new_tree->u.list.elements[0]->u.isnot.child =
+                       talloc(new_tree->u.list.elements, struct ldb_parse_tree);
+               if (!new_tree->u.list.elements[0]->u.isnot.child) {
+                       ldb_oom(ldb);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
-               new_attrs[i+1] = NULL;
-               down_req->op.search.attrs = (const char * const *)new_attrs;
+               new_tree->u.list.elements[0]->u.isnot.child->operation = LDB_OP_EQUALITY;
+               new_tree->u.list.elements[0]->u.isnot.child->u.equality.attr = "isDeleted";
+               new_tree->u.list.elements[0]->u.isnot.child->u.equality.value = data_blob_string_const("TRUE");
+               new_tree->u.list.elements[1] = req->op.search.tree;
+       }
+       
+       ret = ldb_build_search_req_ex(&down_req, ldb, req,
+                                     req->op.search.base,
+                                     req->op.search.scope,
+                                     new_tree,
+                                     req->op.search.attrs,
+                                     req->controls,
+                                     req->context, req->callback,
+                                     req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
        }
 
-       down_req->context = ar;
-       down_req->callback = show_deleted_search_callback;
-       ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
-next_request:
-       /* perform the search */
-       ret = ldb_next_request(module, down_req);
-
-       /* do not free down_req as the call results may be linked to it,
-        * it will be freed when the upper level request get freed */
-       if (ret == LDB_SUCCESS) {
-               req->handle = down_req->handle;
+       /* mark the control as done */
+       if (control) {
+               control->critical = 0;
        }
 
-       return ret;
+       /* perform the search */
+       return ldb_next_request(module, down_req);
 }
 
 static int show_deleted_init(struct ldb_module *module)
 {
-       struct ldb_request *req;
+       struct ldb_context *ldb;
        int ret;
 
-       req = talloc(module, struct ldb_request);
-       if (req == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       req->operation = LDB_REQ_REGISTER_CONTROL;
-       req->op.reg_control.oid = LDB_CONTROL_SHOW_DELETED_OID;
-       req->controls = NULL;
+       ldb = ldb_module_get_ctx(module);
 
-       ret = ldb_request(module->ldb, req);
+       ret = ldb_mod_register_control(module, LDB_CONTROL_SHOW_DELETED_OID);
        if (ret != LDB_SUCCESS) {
-               ldb_debug(module->ldb, LDB_DEBUG_ERROR, "show_deleted: Unable to register control with rootdse!\n");
-               talloc_free(req);
+               ldb_debug(ldb, LDB_DEBUG_ERROR,
+                       "show_deleted: Unable to register control with rootdse!\n");
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       talloc_free(req);
        return ldb_next_init(module);
 }