4 Copyright (C) Simo Sorce 2005
5 Copyright (C) Stefa Metzmacher <metze@samba.org> 2007
7 ** NOTE! The following LGPL license applies to the ldb
8 ** library. This does NOT imply that all of Samba is released
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
28 * Component: ldb deleted objects control module
30 * Description: this module hides deleted objects, and returns them if the control is there
32 * Author: Stefan Metzmacher
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_errors.h"
38 #include "ldb/include/ldb_private.h"
39 #include "dsdb/samdb/samdb.h"
42 struct show_deleted_search_request {
44 struct ldb_module *module;
46 int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
51 static int show_deleted_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
53 struct show_deleted_search_request *ar;
55 ar = talloc_get_type(context, struct show_deleted_search_request);
57 if (ares->type == LDB_REPLY_ENTRY) {
60 isDeleted = ldb_msg_find_attr_as_bool(ares->message, "isDeleted", false);
66 if (ar->remove_from_msg) {
67 ldb_msg_remove_attr(ares->message, "isDeleted");
71 return ar->up_callback(ldb, ar->up_context, ares);
78 static int show_deleted_search(struct ldb_module *module, struct ldb_request *req)
80 struct ldb_control *control;
81 struct ldb_control **saved_controls;
82 struct show_deleted_search_request *ar;
83 struct ldb_request *down_req;
85 uint32_t num_attrs = 0;
89 /* check if there's a show deleted control */
90 control = ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID);
92 /* copy the request for modification */
93 down_req = talloc(req, struct ldb_request);
94 if (down_req == NULL) {
96 return LDB_ERR_OPERATIONS_ERROR;
99 /* copy the request */
102 /* if a control is there remove if from the modified request */
103 if (control && !save_controls(control, down_req, &saved_controls)) {
104 return LDB_ERR_OPERATIONS_ERROR;
107 /* if we had a control, then just go on to the next request as we have nothing to hide */
112 ar = talloc(down_req, struct show_deleted_search_request);
114 ldb_oom(module->ldb);
115 return LDB_ERR_OPERATIONS_ERROR;
119 ar->up_context = req->context;
120 ar->up_callback = req->callback;
121 ar->remove_from_msg = true;
123 /* check if attrs only is specified, in that case check wether we need to modify them */
124 if (down_req->op.search.attrs) {
125 for (i=0; (down_req->op.search.attrs && down_req->op.search.attrs[i]); i++) {
127 if (strcasecmp(down_req->op.search.attrs[i], "*") == 0) {
128 ar->remove_from_msg = false;
129 } else if (strcasecmp(down_req->op.search.attrs[i], "isDeleted") == 0) {
130 ar->remove_from_msg = false;
134 ar->remove_from_msg = false;
137 if (ar->remove_from_msg) {
138 new_attrs = talloc_array(down_req, char *, num_attrs + 2);
140 ldb_oom(module->ldb);
141 return LDB_ERR_OPERATIONS_ERROR;
143 for (i=0; i < num_attrs; i++) {
144 new_attrs[i] = discard_const_p(char, down_req->op.search.attrs[i]);
146 new_attrs[i] = talloc_strdup(new_attrs, "isDeleted");
148 ldb_oom(module->ldb);
149 return LDB_ERR_OPERATIONS_ERROR;
151 new_attrs[i+1] = NULL;
152 down_req->op.search.attrs = (const char * const *)new_attrs;
155 down_req->context = ar;
156 down_req->callback = show_deleted_search_callback;
157 ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
160 /* perform the search */
161 ret = ldb_next_request(module, down_req);
163 /* do not free down_req as the call results may be linked to it,
164 * it will be freed when the upper level request get freed */
165 if (ret == LDB_SUCCESS) {
166 req->handle = down_req->handle;
172 static int show_deleted_init(struct ldb_module *module)
174 struct ldb_request *req;
177 req = talloc(module, struct ldb_request);
179 return LDB_ERR_OPERATIONS_ERROR;
182 req->operation = LDB_REQ_REGISTER_CONTROL;
183 req->op.reg_control.oid = LDB_CONTROL_SHOW_DELETED_OID;
184 req->controls = NULL;
186 ret = ldb_request(module->ldb, req);
187 if (ret != LDB_SUCCESS) {
188 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "show_deleted: Unable to register control with rootdse!\n");
190 return LDB_ERR_OPERATIONS_ERROR;
194 return ldb_next_init(module);
197 static const struct ldb_module_ops show_deleted_ops = {
198 .name = "show_deleted",
199 .search = show_deleted_search,
200 .init_context = show_deleted_init
203 int ldb_show_deleted_init(void)
205 return ldb_register_module(&show_deleted_ops);