4 Copyright (C) Simo Sorce 2005
5 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
7 Copyright (C) Matthias Dieter Wallnöfer 2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb deleted objects control module
28 * Description: this module hides deleted and recylced objects, and returns
29 * them if the right control is there
31 * Author: Stefan Metzmacher
35 #include <ldb_module.h>
36 #include "dsdb/samdb/samdb.h"
37 #include "dsdb/samdb/ldb_modules/util.h"
39 struct show_deleted_state {
41 bool recycle_bin_enabled;
44 static int show_deleted_search(struct ldb_module *module, struct ldb_request *req)
46 struct ldb_context *ldb;
47 struct ldb_control *show_del, *show_rec;
48 struct ldb_request *down_req;
49 struct ldb_parse_tree *new_tree = req->op.search.tree;
50 struct show_deleted_state *state;
52 const char *attr_filter = NULL;
54 /* do not manipulate our control entries */
55 if (ldb_dn_is_special(req->op.search.base)) {
56 return ldb_next_request(module, req);
59 ldb = ldb_module_get_ctx(module);
61 state = talloc_get_type(ldb_module_get_private(module), struct show_deleted_state);
63 /* note that state may be NULL during initialisation */
64 if (state != NULL && state->need_refresh) {
65 /* Do not move this assignment, it can cause recursion loops! */
66 state->need_refresh = false;
67 ret = dsdb_recyclebin_enabled(module, &state->recycle_bin_enabled);
68 if (ret != LDB_SUCCESS) {
69 state->recycle_bin_enabled = false;
71 * We can fail to find the feature object
72 * during provision. Ignore any such error and
73 * assume the recycle bin cannot be enabled at
76 if (ret != LDB_ERR_NO_SUCH_OBJECT) {
77 state->need_refresh = true;
78 return LDB_ERR_UNWILLING_TO_PERFORM;
83 /* This is the logic from MS-ADTS 3.1.1.3.4.1.14 that
84 determines if objects are visible
86 Extended control name Deleted-objects Tombstones Recycled-objects
87 LDAP_SERVER_SHOW_DELETED_OID Visible Visible Not Visible
88 LDAP_SERVER_SHOW_RECYCLED_OID Visible Visible Visible
90 Note that if the recycle bin is disabled, then the
91 isRecycled attribute is ignored, and objects are either
92 "normal" or "tombstone".
94 When the recycle bin is enabled, then objects are in one of
95 3 states, "normal", "deleted" or "recycled"
98 /* check if there's a show deleted control */
99 show_del = ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID);
100 /* check if there's a show recycled control */
101 show_rec = ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID);
104 if (state == NULL || !state->recycle_bin_enabled) {
105 /* when recycle bin is not enabled, then all we look
106 at is the isDeleted attribute. We hide objects with this
107 attribute set to TRUE when the client has not specified either
108 SHOW_DELETED or SHOW_RECYCLED
110 if (show_del != NULL || show_rec != NULL) {
113 attr_filter = "isDeleted";
116 /* the recycle bin is enabled
118 if (show_rec != NULL) {
120 } else if (show_del != NULL) {
121 /* we want deleted but not recycled objects */
122 attr_filter = "isRecycled";
124 /* we don't want deleted or recycled objects,
125 * which we get by filtering on isDeleted */
126 attr_filter = "isDeleted";
131 if (attr_filter != NULL) {
132 new_tree = talloc(req, struct ldb_parse_tree);
136 new_tree->operation = LDB_OP_AND;
137 new_tree->u.list.num_elements = 2;
138 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, 2);
139 if (!new_tree->u.list.elements) {
143 new_tree->u.list.elements[0] = talloc(new_tree->u.list.elements, struct ldb_parse_tree);
144 new_tree->u.list.elements[0]->operation = LDB_OP_NOT;
145 new_tree->u.list.elements[0]->u.isnot.child =
146 talloc(new_tree->u.list.elements, struct ldb_parse_tree);
147 if (!new_tree->u.list.elements[0]->u.isnot.child) {
150 new_tree->u.list.elements[0]->u.isnot.child->operation = LDB_OP_EQUALITY;
151 new_tree->u.list.elements[0]->u.isnot.child->u.equality.attr = attr_filter;
152 new_tree->u.list.elements[0]->u.isnot.child->u.equality.value = data_blob_string_const("TRUE");
153 new_tree->u.list.elements[1] = req->op.search.tree;
156 ret = ldb_build_search_req_ex(&down_req, ldb, req,
158 req->op.search.scope,
160 req->op.search.attrs,
162 req, dsdb_next_callback,
164 LDB_REQ_SET_LOCATION(down_req);
165 if (ret != LDB_SUCCESS) {
169 /* mark the controls as done */
170 if (show_del != NULL) {
171 show_del->critical = 0;
173 if (show_rec != NULL) {
174 show_rec->critical = 0;
177 /* perform the search */
178 return ldb_next_request(module, down_req);
181 static int show_deleted_init(struct ldb_module *module)
183 struct ldb_context *ldb;
185 struct show_deleted_state *state;
187 state = talloc_zero(module, struct show_deleted_state);
189 return ldb_module_oom(module);
191 state->need_refresh = true;
193 ldb = ldb_module_get_ctx(module);
195 ret = ldb_mod_register_control(module, LDB_CONTROL_SHOW_DELETED_OID);
196 if (ret != LDB_SUCCESS) {
197 ldb_debug(ldb, LDB_DEBUG_ERROR,
198 "show_deleted: Unable to register control with rootdse!\n");
199 return ldb_operr(ldb);
202 ret = ldb_mod_register_control(module, LDB_CONTROL_SHOW_RECYCLED_OID);
203 if (ret != LDB_SUCCESS) {
204 ldb_debug(ldb, LDB_DEBUG_ERROR,
205 "show_deleted: Unable to register control with rootdse!\n");
206 return ldb_operr(ldb);
209 ret = ldb_next_init(module);
211 ldb_module_set_private(module, state);
216 static const struct ldb_module_ops ldb_show_deleted_module_ops = {
217 .name = "show_deleted",
218 .search = show_deleted_search,
219 .init_context = show_deleted_init
222 int ldb_show_deleted_module_init(const char *version)
224 LDB_MODULE_CHECK_VERSION(version);
225 return ldb_register_module(&ldb_show_deleted_module_ops);