r25761: Rename to be a DN to be a child of itself wasn't being checked for.
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / subtree_rename.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2007
5    Copyright (C) Stefan 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 3 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, see <http://www.gnu.org/licenses/>.
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb subtree rename module
29  *
30  *  Description: Rename a subtree in LDB
31  *
32  *  Author: Andrew Bartlett
33  */
34
35 #include "ldb_includes.h"
36
37 struct subtree_rename_context {
38         struct ldb_module *module;
39         struct ldb_handle *handle;
40         struct ldb_request *orig_req;
41
42         struct ldb_request **down_req;
43         int num_requests;
44         int finished_requests;
45
46         int num_children;
47 };
48
49 static struct subtree_rename_context *subtree_rename_init_handle(struct ldb_request *req, 
50                                                                  struct ldb_module *module)
51 {
52         struct subtree_rename_context *ac;
53         struct ldb_handle *h;
54
55         h = talloc_zero(req, struct ldb_handle);
56         if (h == NULL) {
57                 ldb_set_errstring(module->ldb, "Out of Memory");
58                 return NULL;
59         }
60
61         h->module = module;
62
63         ac = talloc_zero(h, struct subtree_rename_context);
64         if (ac == NULL) {
65                 ldb_set_errstring(module->ldb, "Out of Memory");
66                 talloc_free(h);
67                 return NULL;
68         }
69
70         h->private_data = ac;
71
72         ac->module = module;
73         ac->handle = h;
74         ac->orig_req = req;
75
76         req->handle = h;
77
78         return ac;
79 }
80
81
82 static int subtree_rename_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) 
83 {
84         struct ldb_request *req;
85         struct subtree_rename_context *ac = talloc_get_type(context, struct subtree_rename_context);
86         TALLOC_CTX *mem_ctx = talloc_new(ac);
87     
88         if (!mem_ctx) {
89                 ldb_oom(ac->module->ldb);
90                 return LDB_ERR_OPERATIONS_ERROR;
91         }
92         /* OK, we have one of *many* search results here:
93
94            We should also get the entry we tried to rename.  This
95            callback handles this and everything below it.
96          */
97
98         /* Only entries are interesting, and we handle the case of the parent seperatly */
99         if (ares->type == LDB_REPLY_ENTRY
100             && ldb_dn_compare(ares->message->dn, ac->orig_req->op.rename.olddn) != 0) {
101                 /* And it is an actual entry: now create a rename from it */
102                 int ret;
103
104                 struct ldb_dn *newdn = ldb_dn_copy(mem_ctx, ares->message->dn);
105                 if (!newdn) {
106                         ldb_oom(ac->module->ldb);
107                         return LDB_ERR_OPERATIONS_ERROR;
108                 }
109                         
110                 ldb_dn_remove_base_components(newdn, ldb_dn_get_comp_num(ac->orig_req->op.rename.olddn));
111
112                 if (!ldb_dn_add_base(newdn, ac->orig_req->op.rename.newdn)) {
113                         ldb_oom(ac->module->ldb);
114                         return LDB_ERR_OPERATIONS_ERROR;
115                 }
116
117                 ret = ldb_build_rename_req(&req, ldb, mem_ctx,
118                                            ares->message->dn,
119                                            newdn,
120                                            NULL,
121                                            NULL,
122                                            NULL);
123                 
124                 if (ret != LDB_SUCCESS) return ret;
125
126                 talloc_steal(req, newdn);
127
128                 talloc_steal(req, ares->message->dn);
129                 
130                 talloc_free(ares);
131                 
132         } else if (ares->type == LDB_REPLY_DONE) {
133                 req = talloc(mem_ctx, struct ldb_request);
134                 *req = *ac->orig_req;
135                 talloc_free(ares);
136
137         } else {
138                 talloc_free(ares);
139                 return LDB_SUCCESS;
140         }
141         
142         ac->down_req = talloc_realloc(ac, ac->down_req, 
143                                       struct ldb_request *, ac->num_requests + 1);
144         if (!ac->down_req) {
145                 ldb_oom(ac->module->ldb);
146                 return LDB_ERR_OPERATIONS_ERROR;
147         }
148         ac->down_req[ac->num_requests] = req;
149         ac->num_requests++;
150         
151         return ldb_next_request(ac->module, req);
152         
153 }
154
155 /* rename */
156 static int subtree_rename(struct ldb_module *module, struct ldb_request *req)
157 {
158         const char *attrs[] = { NULL };
159         struct ldb_request *new_req;
160         struct subtree_rename_context *ac;
161         int ret;
162         if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
163                 return ldb_next_request(module, req);
164         }
165
166         /* Firstly ensure we are not trying to rename it to be a child of itself */
167         if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
168             && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
169                 ldb_asprintf_errstring(module->ldb, "Cannot rename %s to be a child of itself",
170                                        ldb_dn_get_linearized(req->op.rename.olddn));
171                 return LDB_ERR_UNWILLING_TO_PERFORM;
172         }
173
174         /* This gets complex:  We need to:
175            - Do a search for all entires under this entry 
176            - Wait for these results to appear
177            - In the callback for each result, issue a modify request
178             - That will include this rename, we hope
179            - Wait for each modify result
180            - Regain our sainity 
181         */
182
183         ac = subtree_rename_init_handle(req, module);
184         if (!ac) {
185                 return LDB_ERR_OPERATIONS_ERROR;
186         }
187
188         ret = ldb_build_search_req(&new_req, module->ldb, req,
189                                    req->op.rename.olddn, 
190                                    LDB_SCOPE_SUBTREE,
191                                    "(objectClass=*)",
192                                    attrs,
193                                    req->controls,
194                                    ac, 
195                                    subtree_rename_search_callback);
196
197         if (ret != LDB_SUCCESS) {
198                 return ret;
199         }
200
201         ac->down_req = talloc_realloc(ac, ac->down_req, 
202                                         struct ldb_request *, ac->num_requests + 1);
203         if (!ac->down_req) {
204                 ldb_oom(ac->module->ldb);
205                 return LDB_ERR_OPERATIONS_ERROR;
206         }
207         ac->down_req[ac->num_requests] = new_req;
208         if (req == NULL) {
209                 ldb_oom(ac->module->ldb);
210                 return LDB_ERR_OPERATIONS_ERROR;
211         }
212         ac->num_requests++;
213         return ldb_next_request(module, new_req);
214 }
215
216
217 static int subtree_delete_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) 
218 {
219         struct ldb_request *req;
220         struct subtree_rename_context *ac = talloc_get_type(context, struct subtree_rename_context);
221         TALLOC_CTX *mem_ctx = talloc_new(ac);
222     
223         if (!mem_ctx) {
224                 ldb_oom(ac->module->ldb);
225                 return LDB_ERR_OPERATIONS_ERROR;
226         }
227         /* OK, we have one of *many* search results here:
228
229            We should also get the entry we tried to rename.  This
230            callback handles this and everything below it.
231          */
232
233         /* Only entries are interesting, and we handle the case of the parent seperatly */
234         if (ares->type == LDB_REPLY_ENTRY
235             && ldb_dn_compare(ares->message->dn, ac->orig_req->op.del.dn) != 0) {
236                 /* And it is an actual entry: now object bitterly that we are not a leaf node */
237                 ac->num_children++;
238                 talloc_free(ares);
239                 return LDB_SUCCESS;
240         } else if (ares->type == LDB_REPLY_DONE) {
241                 talloc_free(ares);
242                 if (ac->num_children > 0) {
243                         ldb_asprintf_errstring(ac->module->ldb, "Cannot delete %s, not a leaf node (has %d children)\n",
244                                             ldb_dn_get_linearized(ac->orig_req->op.del.dn), ac->num_children);
245                         return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
246                 } else {
247                         req = talloc(mem_ctx, struct ldb_request);
248                         if (!req) {
249                                 ldb_oom(ac->module->ldb);
250                                 return LDB_ERR_OPERATIONS_ERROR;
251                         }
252                         *req = *ac->orig_req;
253                         
254                         ac->down_req = talloc_realloc(ac, ac->down_req, 
255                                                       struct ldb_request *, ac->num_requests + 1);
256                         if (!ac->down_req) {
257                                 ldb_oom(ac->module->ldb);
258                                 return LDB_ERR_OPERATIONS_ERROR;
259                         }
260                         ac->down_req[ac->num_requests] = req;
261                         ac->num_requests++;
262                         
263                         return ldb_next_request(ac->module, req);
264                 }
265         } else {
266                 talloc_free(ares);
267                 return LDB_SUCCESS;
268         }
269 }
270
271 /* rename */
272 static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
273 {
274         const char *attrs[] = { NULL };
275         struct ldb_request *new_req;
276         struct subtree_rename_context *ac;
277         int ret;
278         if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
279                 return ldb_next_request(module, req);
280         }
281
282         /* This gets complex:  We need to:
283            - Do a search for all entires under this entry 
284            - Wait for these results to appear
285            - In the callback for each result, issue a modify request
286             - That will include this rename, we hope
287            - Wait for each modify result
288            - Regain our sainity 
289         */
290
291         ac = subtree_rename_init_handle(req, module);
292         if (!ac) {
293                 return LDB_ERR_OPERATIONS_ERROR;
294         }
295
296         ret = ldb_build_search_req(&new_req, module->ldb, req,
297                                    req->op.del.dn, 
298                                    LDB_SCOPE_SUBTREE,
299                                    "(objectClass=*)",
300                                    attrs,
301                                    req->controls,
302                                    ac, 
303                                    subtree_delete_search_callback);
304
305         if (ret != LDB_SUCCESS) {
306                 return ret;
307         }
308
309         ac->down_req = talloc_realloc(ac, ac->down_req, 
310                                         struct ldb_request *, ac->num_requests + 1);
311         if (!ac->down_req) {
312                 ldb_oom(ac->module->ldb);
313                 return LDB_ERR_OPERATIONS_ERROR;
314         }
315         ac->down_req[ac->num_requests] = new_req;
316         if (req == NULL) {
317                 ldb_oom(ac->module->ldb);
318                 return LDB_ERR_OPERATIONS_ERROR;
319         }
320         ac->num_requests++;
321         return ldb_next_request(module, new_req);
322 }
323
324 static int subtree_rename_wait_none(struct ldb_handle *handle) {
325         struct subtree_rename_context *ac;
326         int i, ret = LDB_ERR_OPERATIONS_ERROR;
327         if (!handle || !handle->private_data) {
328                 return LDB_ERR_OPERATIONS_ERROR;
329         }
330
331         if (handle->state == LDB_ASYNC_DONE) {
332                 return handle->status;
333         }
334
335         handle->state = LDB_ASYNC_PENDING;
336         handle->status = LDB_SUCCESS;
337
338         ac = talloc_get_type(handle->private_data, struct subtree_rename_context);
339
340         for (i=0; i < ac->num_requests; i++) {
341                 ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
342                 
343                 if (ret != LDB_SUCCESS) {
344                         handle->status = ret;
345                         goto done;
346                 }
347                 if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
348                         handle->status = ac->down_req[i]->handle->status;
349                         goto done;
350                 }
351                 
352                 if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
353                         return LDB_SUCCESS;
354                 }
355         }
356
357 done:
358         handle->state = LDB_ASYNC_DONE;
359         return ret;
360
361 }
362
363 static int subtree_rename_wait_all(struct ldb_handle *handle) {
364
365         int ret;
366
367         while (handle->state != LDB_ASYNC_DONE) {
368                 ret = subtree_rename_wait_none(handle);
369                 if (ret != LDB_SUCCESS) {
370                         return ret;
371                 }
372         }
373
374         return handle->status;
375 }
376
377 static int subtree_rename_wait(struct ldb_handle *handle, enum ldb_wait_type type)
378 {
379         if (type == LDB_WAIT_ALL) {
380                 return subtree_rename_wait_all(handle);
381         } else {
382                 return subtree_rename_wait_none(handle);
383         }
384 }
385
386 static const struct ldb_module_ops subtree_rename_ops = {
387         .name              = "subtree_rename",
388         .rename            = subtree_rename,
389         .del               = subtree_delete,
390         .wait              = subtree_rename_wait,
391 };
392
393 int ldb_subtree_rename_init(void)
394 {
395         return ldb_register_module(&subtree_rename_ops);
396 }