50e0e675c50ecda735e2398ae46263cffe901e9e
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / show_deleted.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2005
5    Copyright (C) Stefa Metzmacher <metze@samba.org> 2007
6
7      ** NOTE! The following LGPL license applies to the ldb
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10    
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.
15
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.
20
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
24 */
25
26 /*
27  *  Name: ldb
28  *
29  *  Component: ldb deleted objects control module
30  *
31  *  Description: this module hides deleted objects, and returns them if the control is there
32  *
33  *  Author: Stefan Metzmacher
34  */
35
36 #include "includes.h"
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"
41
42 /* search */
43 struct show_deleted_search_request {
44
45         struct ldb_module *module;
46         void *up_context;
47         int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
48
49         bool remove_from_msg;
50 };
51
52 static int show_deleted_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
53 {
54         struct show_deleted_search_request *ar;
55
56         if (!context || !ares) {
57                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
58                 goto error;
59         }
60
61         ar = talloc_get_type(context, struct show_deleted_search_request);
62
63         if (ares->type == LDB_REPLY_ENTRY) {
64                 bool isDeleted;
65
66                 isDeleted = ldb_msg_find_attr_as_bool(ares->message, "isDeleted", false);
67
68                 if (isDeleted) {
69                         goto skip_deleted;
70                 }
71
72                 if (ar->remove_from_msg) {
73                         ldb_msg_remove_attr(ares->message, "isDeleted");
74                 }
75         }
76
77         return ar->up_callback(ldb, ar->up_context, ares);
78
79 skip_deleted:
80         talloc_free(ares);
81         return LDB_SUCCESS;
82 error:
83         talloc_free(ares);
84         return LDB_ERR_OPERATIONS_ERROR;
85 }
86
87 static int show_deleted_search(struct ldb_module *module, struct ldb_request *req)
88 {
89         struct ldb_control *control;
90         struct ldb_control **saved_controls;
91         struct show_deleted_search_request *ar;
92         struct ldb_request *down_req;
93         char **new_attrs;
94         uint32_t num_attrs = 0;
95         uint32_t i;
96         int ret;
97
98         /* check if there's a show deleted control */
99         control = ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID);
100
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;
106         }
107
108         /* copy the request */
109         *down_req = *req;
110
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;
114         }
115
116         /* if we had a control, then just go on to the next request as we have nothing to hide */
117         if (control) {
118                 goto next_request;
119         }
120
121         ar = talloc(down_req, struct show_deleted_search_request);
122         if (ar == NULL) {
123                 ldb_oom(module->ldb);
124                 return LDB_ERR_OPERATIONS_ERROR;
125         }
126
127         ar->module              = module;
128         ar->up_context          = req->context;
129         ar->up_callback         = req->callback;
130         ar->remove_from_msg     = true;
131
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++) {
135                         num_attrs++;
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;
140                         }
141                 }
142         } else {
143                 ar->remove_from_msg = false;
144         }
145
146         if (ar->remove_from_msg) {
147                 new_attrs = talloc_array(down_req, char *, num_attrs + 2);
148                 if (!new_attrs) {
149                         ldb_oom(module->ldb);
150                         return LDB_ERR_OPERATIONS_ERROR;
151                 }
152                 for (i=0; i < num_attrs; i++) {
153                         new_attrs[i] = discard_const_p(char, down_req->op.search.attrs[i]);             
154                 }
155                 new_attrs[i] = talloc_strdup(new_attrs, "isDeleted");
156                 if (!new_attrs[i]) {
157                         ldb_oom(module->ldb);
158                         return LDB_ERR_OPERATIONS_ERROR;
159                 }
160                 new_attrs[i+1] = NULL;
161                 down_req->op.search.attrs = (const char * const *)new_attrs;
162         }
163
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);
167
168 next_request:
169         /* perform the search */
170         ret = ldb_next_request(module, down_req);
171
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;
176         }
177
178         return ret;
179 }
180
181 static int show_deleted_init(struct ldb_module *module)
182 {
183         struct ldb_request *req;
184         int ret;
185
186         req = talloc(module, struct ldb_request);
187         if (req == NULL) {
188                 return LDB_ERR_OPERATIONS_ERROR;
189         }
190
191         req->operation = LDB_REQ_REGISTER_CONTROL;
192         req->op.reg_control.oid = LDB_CONTROL_SHOW_DELETED_OID;
193         req->controls = NULL;
194
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");
198                 talloc_free(req);
199                 return LDB_ERR_OPERATIONS_ERROR;
200         }
201
202         talloc_free(req);
203         return ldb_next_init(module);
204 }
205
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
210 };
211
212 int ldb_show_deleted_init(void)
213 {
214         return ldb_register_module(&show_deleted_ops);
215 }