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 2 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, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Component: ldb deleted objects control module
31 * Description: this module hides deleted objects, and returns them if the control is there
33 * Author: Stefan Metzmacher
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_errors.h"
39 #include "ldb/include/ldb_private.h"
40 #include "dsdb/samdb/samdb.h"
43 struct show_deleted_search_request {
45 struct ldb_module *module;
47 int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
52 static int show_deleted_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
54 struct show_deleted_search_request *ar;
56 if (!context || !ares) {
57 ldb_set_errstring(ldb, "NULL Context or Result in callback");
61 ar = talloc_get_type(context, struct show_deleted_search_request);
63 if (ares->type == LDB_REPLY_ENTRY) {
66 isDeleted = ldb_msg_find_attr_as_bool(ares->message, "isDeleted", false);
72 if (ar->remove_from_msg) {
73 ldb_msg_remove_attr(ares->message, "isDeleted");
77 return ar->up_callback(ldb, ar->up_context, ares);
84 return LDB_ERR_OPERATIONS_ERROR;
87 static int show_deleted_search(struct ldb_module *module, struct ldb_request *req)
89 struct ldb_control *control;
90 struct ldb_control **saved_controls;
91 struct show_deleted_search_request *ar;
92 struct ldb_request *down_req;
94 uint32_t num_attrs = 0;
98 /* check if there's a show deleted control */
99 control = ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID);
101 /* copy the request for modification */
102 down_req = talloc(req, struct ldb_request);
103 if (down_req == NULL) {
104 ldb_oom(module->ldb);
105 return LDB_ERR_OPERATIONS_ERROR;
108 /* copy the request */
111 /* if a control is there remove if from the modified request */
112 if (control && !save_controls(control, down_req, &saved_controls)) {
113 return LDB_ERR_OPERATIONS_ERROR;
116 /* if we had a control, then just go on to the next request as we have nothing to hide */
121 ar = talloc(down_req, struct show_deleted_search_request);
123 ldb_oom(module->ldb);
124 return LDB_ERR_OPERATIONS_ERROR;
128 ar->up_context = req->context;
129 ar->up_callback = req->callback;
130 ar->remove_from_msg = true;
132 /* check if attrs only is specified, in that case check wether we need to modify them */
133 if (down_req->op.search.attrs) {
134 for (i=0; (down_req->op.search.attrs && down_req->op.search.attrs[i]); i++) {
136 if (strcasecmp(down_req->op.search.attrs[i], "*") == 0) {
137 ar->remove_from_msg = false;
138 } else if (strcasecmp(down_req->op.search.attrs[i], "isDeleted") == 0) {
139 ar->remove_from_msg = false;
143 ar->remove_from_msg = false;
146 if (ar->remove_from_msg) {
147 new_attrs = talloc_array(down_req, char *, num_attrs + 2);
149 ldb_oom(module->ldb);
150 return LDB_ERR_OPERATIONS_ERROR;
152 for (i=0; i < num_attrs; i++) {
153 new_attrs[i] = discard_const_p(char, down_req->op.search.attrs[i]);
155 new_attrs[i] = talloc_strdup(new_attrs, "isDeleted");
157 ldb_oom(module->ldb);
158 return LDB_ERR_OPERATIONS_ERROR;
160 new_attrs[i+1] = NULL;
161 down_req->op.search.attrs = (const char * const *)new_attrs;
164 down_req->context = ar;
165 down_req->callback = show_deleted_search_callback;
166 ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
169 /* perform the search */
170 ret = ldb_next_request(module, down_req);
172 /* do not free down_req as the call results may be linked to it,
173 * it will be freed when the upper level request get freed */
174 if (ret == LDB_SUCCESS) {
175 req->handle = down_req->handle;
181 static int show_deleted_init(struct ldb_module *module)
183 struct ldb_request *req;
186 req = talloc(module, struct ldb_request);
188 return LDB_ERR_OPERATIONS_ERROR;
191 req->operation = LDB_REQ_REGISTER_CONTROL;
192 req->op.reg_control.oid = LDB_CONTROL_SHOW_DELETED_OID;
193 req->controls = NULL;
195 ret = ldb_request(module->ldb, req);
196 if (ret != LDB_SUCCESS) {
197 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "show_deleted: Unable to register control with rootdse!\n");
199 return LDB_ERR_OPERATIONS_ERROR;
203 return ldb_next_init(module);
206 static const struct ldb_module_ops show_deleted_ops = {
207 .name = "show_deleted",
208 .search = show_deleted_search,
209 .init_context = show_deleted_init
212 int ldb_show_deleted_init(void)
214 return ldb_register_module(&show_deleted_ops);