83eec1d5558c754672c700ba5221cc022037dc4d
[sfrench/samba-autobuild/.git] / source4 / lib / ldb / ldb_map / ldb_map_inbound.c
1 /*
2    ldb database mapping module
3
4    Copyright (C) Jelmer Vernooij 2005
5    Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6    Copyright (C) Simo Sorce <idra@samba.org> 2008
7
8      ** NOTE! The following LGPL license applies to the ldb
9      ** library. This does NOT imply that all of Samba is released
10      ** under the LGPL
11    
12    This library is free software; you can redistribute it and/or
13    modify it under the terms of the GNU Lesser General Public
14    License as published by the Free Software Foundation; either
15    version 3 of the License, or (at your option) any later version.
16
17    This library is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    Lesser General Public License for more details.
21
22    You should have received a copy of the GNU Lesser General Public
23    License along with this library; if not, see <http://www.gnu.org/licenses/>.
24
25 */
26
27 #include "ldb_includes.h"
28 #include "ldb_map.h"
29 #include "ldb_map_private.h"
30
31
32 /* Mapping message elements
33  * ======================== */
34
35 /* Map a message element into the remote partition. */
36 static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old)
37 {
38         struct ldb_message_element *el;
39         unsigned int i;
40
41         el = talloc_zero(mem_ctx, struct ldb_message_element);
42         if (el == NULL) {
43                 map_oom(module);
44                 return NULL;
45         }
46
47         el->num_values = old->num_values;
48         el->values = talloc_array(el, struct ldb_val, el->num_values);
49         if (el->values == NULL) {
50                 talloc_free(el);
51                 map_oom(module);
52                 return NULL;
53         }
54
55         el->name = map_attr_map_local(el, map, old->name);
56
57         for (i = 0; i < el->num_values; i++) {
58                 el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
59         }
60
61         return el;
62 }
63
64 /* Add a message element either to a local or to a remote message,
65  * depending on whether it goes into the local or remote partition. */
66 static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old)
67 {
68         const struct ldb_map_context *data = map_get_context(module);
69         const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
70         struct ldb_message_element *el=NULL;
71         struct ldb_context *ldb = ldb_module_get_ctx(module);
72
73         /* Unknown attribute: ignore */
74         if (map == NULL) {
75                 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
76                           "Not mapping attribute '%s': no mapping found",
77                           old->name);
78                 goto local;
79         }
80
81         switch (map->type) {
82         case LDB_MAP_IGNORE:
83                 goto local;
84
85         case LDB_MAP_CONVERT:
86                 if (map->u.convert.convert_local == NULL) {
87                         ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
88                                   "Not mapping attribute '%s': "
89                                   "'convert_local' not set",
90                                   map->local_name);
91                         goto local;
92                 }
93                 /* fall through */
94         case LDB_MAP_KEEP:
95         case LDB_MAP_RENAME:
96                 el = ldb_msg_el_map_local(module, remote, map, old);
97                 break;
98
99         case LDB_MAP_GENERATE:
100                 if (map->u.generate.generate_remote == NULL) {
101                         ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
102                                   "Not mapping attribute '%s': "
103                                   "'generate_remote' not set",
104                                   map->local_name);
105                         goto local;
106                 }
107
108                 /* TODO: if this attr requires context:
109                  *       make sure all context attrs are mappable (in 'names')
110                  *       make sure all context attrs have already been mapped?
111                  *       maybe postpone generation until they have been mapped?
112                  */
113
114                 map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
115                 return 0;
116         }
117
118         if (el == NULL) {
119                 return -1;
120         }
121
122         return ldb_msg_add(remote, el, old->flags);
123
124 local:
125         el = talloc(local, struct ldb_message_element);
126         if (el == NULL) {
127                 map_oom(module);
128                 return -1;
129         }
130
131         *el = *old;                     /* copy the old element */
132
133         return ldb_msg_add(local, el, old->flags);
134 }
135
136 /* Mapping messages
137  * ================ */
138
139 /* Check whether a message will be (partially) mapped into the remote partition. */
140 static bool ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
141 {
142         const struct ldb_map_context *data = map_get_context(module);
143         bool ret;
144         unsigned int i;
145
146         for (i = 0; i < msg->num_elements; i++) {
147                 ret = map_attr_check_remote(data, msg->elements[i].name);
148                 if (ret) {
149                         return ret;
150                 }
151         }
152
153         return false;
154 }
155
156 /* Split message elements that stay in the local partition from those
157  * that are mapped into the remote partition. */
158 static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
159 {
160         /* const char * const names[]; */
161         struct ldb_context *ldb;
162         unsigned int i;
163         int ret;
164
165         ldb = ldb_module_get_ctx(module);
166
167         for (i = 0; i < msg->num_elements; i++) {
168                 /* Skip 'IS_MAPPED' */
169                 if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
170                         ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
171                                   "Skipping attribute '%s'",
172                                   msg->elements[i].name);
173                         continue;
174                 }
175
176                 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
177                 if (ret) {
178                         return ret;
179                 }
180         }
181
182         return 0;
183 }
184
185
186 static int map_add_do_local(struct map_context *ac);
187 static int map_modify_do_local(struct map_context *ac);
188 static int map_delete_do_local(struct map_context *ac);
189 static int map_rename_do_local(struct map_context *ac);
190 static int map_rename_do_fixup(struct map_context *ac);
191 static int map_rename_local_callback(struct ldb_request *req,
192                                      struct ldb_reply *ares);
193
194
195 /*****************************************************************************
196  * COMMON INBOUND functions
197 *****************************************************************************/
198
199 /* Store the DN of a single search result in context. */
200 static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
201 {
202         struct ldb_context *ldb;
203         struct map_context *ac;
204         int ret;
205
206         ac = talloc_get_type(req->context, struct map_context);
207         ldb = ldb_module_get_ctx(ac->module);
208
209         if (!ares) {
210                 return ldb_module_done(ac->req, NULL, NULL,
211                                         LDB_ERR_OPERATIONS_ERROR);
212         }
213         if (ares->error != LDB_SUCCESS) {
214                 return ldb_module_done(ac->req, ares->controls,
215                                         ares->response, ares->error);
216         }
217
218         /* We are interested only in the single reply */
219         switch(ares->type) {
220         case LDB_REPLY_ENTRY:
221                 /* We have already found a remote DN */
222                 if (ac->local_dn) {
223                         ldb_set_errstring(ldb,
224                                           "Too many results!");
225                         return ldb_module_done(ac->req, NULL, NULL,
226                                                 LDB_ERR_OPERATIONS_ERROR);
227                 }
228
229                 /* Store local DN */
230                 ac->local_dn = talloc_steal(ac, ares->message->dn);
231                 break;
232
233         case LDB_REPLY_DONE:
234
235                 switch (ac->req->operation) {
236                 case LDB_MODIFY:
237                         ret = map_modify_do_local(ac);
238                         break;
239                 case LDB_DELETE:
240                         ret = map_delete_do_local(ac);
241                         break;
242                 case LDB_RENAME:
243                         ret = map_rename_do_local(ac);
244                         break;
245                 default:
246                         /* if we get here we have definitely a problem */
247                         ret = LDB_ERR_OPERATIONS_ERROR;
248                 }
249                 if (ret != LDB_SUCCESS) {
250                         return ldb_module_done(ac->req, NULL, NULL,
251                                                 LDB_ERR_OPERATIONS_ERROR);
252                 }
253
254         default:
255                 /* ignore referrals */
256                 break;
257         }
258
259         talloc_free(ares);
260         return LDB_SUCCESS;
261 }
262
263 /* Build a request to search the local record by its DN. */
264 static int map_search_self_req(struct ldb_request **req,
265                                 struct map_context *ac,
266                                 struct ldb_dn *dn)
267 {
268         /* attrs[] is returned from this function in
269          * ac->search_req->op.search.attrs, so it must be static, as
270          * otherwise the compiler can put it on the stack */
271         static const char * const attrs[] = { IS_MAPPED, NULL };
272         struct ldb_parse_tree *tree;
273
274         /* Limit search to records with 'IS_MAPPED' present */
275         tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
276         if (tree == NULL) {
277                 map_oom(ac->module);
278                 return LDB_ERR_OPERATIONS_ERROR;
279         }
280
281         *req = map_search_base_req(ac, dn, attrs, tree,
282                                    ac, map_search_self_callback);
283         if (*req == NULL) {
284                 return LDB_ERR_OPERATIONS_ERROR;
285         }
286
287         return LDB_SUCCESS;
288 }
289
290 static int map_op_local_callback(struct ldb_request *req,
291                                  struct ldb_reply *ares)
292 {
293         struct ldb_context *ldb;
294         struct map_context *ac;
295         int ret;
296
297         ac = talloc_get_type(req->context, struct map_context);
298         ldb = ldb_module_get_ctx(ac->module);
299
300         if (!ares) {
301                 return ldb_module_done(ac->req, NULL, NULL,
302                                         LDB_ERR_OPERATIONS_ERROR);
303         }
304         if (ares->error != LDB_SUCCESS) {
305                 return ldb_module_done(ac->req, ares->controls,
306                                         ares->response, ares->error);
307         }
308
309         if (ares->type != LDB_REPLY_DONE) {
310                 ldb_set_errstring(ldb, "Invalid reply type!");
311                 return ldb_module_done(ac->req, NULL, NULL,
312                                         LDB_ERR_OPERATIONS_ERROR);
313         }
314
315         /* Do the remote request. */
316         ret = ldb_next_remote_request(ac->module, ac->remote_req);
317         if (ret != LDB_SUCCESS) {
318                 return ldb_module_done(ac->req, NULL, NULL,
319                                         LDB_ERR_OPERATIONS_ERROR);
320         }
321
322         return LDB_SUCCESS;
323 }
324
325 static int map_op_remote_callback(struct ldb_request *req,
326                                   struct ldb_reply *ares)
327 {
328         struct ldb_context *ldb;
329         struct map_context *ac;
330
331         ac = talloc_get_type(req->context, struct map_context);
332         ldb = ldb_module_get_ctx(ac->module);
333
334         if (!ares) {
335                 return ldb_module_done(ac->req, NULL, NULL,
336                                         LDB_ERR_OPERATIONS_ERROR);
337         }
338         if (ares->error != LDB_SUCCESS) {
339                 return ldb_module_done(ac->req, ares->controls,
340                                         ares->response, ares->error);
341         }
342
343         if (ares->type != LDB_REPLY_DONE) {
344                 ldb_set_errstring(ldb, "Invalid reply type!");
345                 return ldb_module_done(ac->req, NULL, NULL,
346                                         LDB_ERR_OPERATIONS_ERROR);
347         }
348
349         return ldb_module_done(ac->req, ares->controls,
350                                         ares->response, ares->error);
351 }
352
353
354 /*****************************************************************************
355  * ADD operations
356 *****************************************************************************/
357
358
359 /* Add a record. */
360 int map_add(struct ldb_module *module, struct ldb_request *req)
361 {
362         const struct ldb_message *msg = req->op.add.message;
363         struct ldb_context *ldb;
364         struct map_context *ac;
365         struct ldb_message *remote_msg;
366         int ret;
367
368         ldb = ldb_module_get_ctx(module);
369
370         /* Do not manipulate our control entries */
371         if (ldb_dn_is_special(msg->dn)) {
372                 return ldb_next_request(module, req);
373         }
374
375         /* No mapping requested (perhaps no DN mapping specified), skip to next module */
376         if (!ldb_dn_check_local(module, msg->dn)) {
377                 return ldb_next_request(module, req);
378         }
379
380         /* No mapping needed, fail */
381         if (!ldb_msg_check_remote(module, msg)) {
382                 return LDB_ERR_OPERATIONS_ERROR;
383         }
384
385         /* Prepare context and handle */
386         ac = map_init_context(module, req);
387         if (ac == NULL) {
388                 return LDB_ERR_OPERATIONS_ERROR;
389         }
390
391
392         /* Prepare the local message */
393         ac->local_msg = ldb_msg_new(ac);
394         if (ac->local_msg == NULL) {
395                 map_oom(module);
396                 return LDB_ERR_OPERATIONS_ERROR;
397         }
398         ac->local_msg->dn = msg->dn;
399
400         /* Prepare the remote message */
401         remote_msg = ldb_msg_new(ac);
402         if (remote_msg == NULL) {
403                 map_oom(module);
404                 return LDB_ERR_OPERATIONS_ERROR;
405         }
406         remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
407
408         /* Split local from remote message */
409         ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
410
411         /* Prepare the remote operation */
412         ret = ldb_build_add_req(&ac->remote_req, ldb,
413                                 ac, remote_msg,
414                                 req->controls,
415                                 ac, map_op_remote_callback,
416                                 req);
417         LDB_REQ_SET_LOCATION(ac->remote_req);
418         if (ret != LDB_SUCCESS) {
419                 return LDB_ERR_OPERATIONS_ERROR;
420         }
421
422         if ((ac->local_msg->num_elements == 0) ||
423             ( ! map_check_local_db(ac->module))) {
424                 /* No local data or db, just run the remote request */
425                 return ldb_next_remote_request(ac->module, ac->remote_req);
426         }
427
428         /* Store remote DN in 'IS_MAPPED' */
429         /* TODO: use GUIDs here instead */
430         ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED,
431                                         remote_msg->dn);
432         if (ret != LDB_SUCCESS) {
433                 return LDB_ERR_OPERATIONS_ERROR;
434         }
435
436         return map_add_do_local(ac);
437 }
438
439 /* Add the local record. */
440 static int map_add_do_local(struct map_context *ac)
441 {
442         struct ldb_request *local_req;
443         struct ldb_context *ldb;
444         int ret;
445
446         ldb = ldb_module_get_ctx(ac->module);
447
448         /* Prepare the local operation */
449         ret = ldb_build_add_req(&local_req, ldb, ac,
450                                 ac->local_msg,
451                                 ac->req->controls,
452                                 ac,
453                                 map_op_local_callback,
454                                 ac->req);
455         LDB_REQ_SET_LOCATION(local_req);
456         if (ret != LDB_SUCCESS) {
457                 return LDB_ERR_OPERATIONS_ERROR;
458         }
459         return ldb_next_request(ac->module, local_req);
460 }
461
462 /*****************************************************************************
463  * MODIFY operations
464 *****************************************************************************/
465
466 /* Modify a record. */
467 int map_modify(struct ldb_module *module, struct ldb_request *req)
468 {
469         const struct ldb_message *msg = req->op.mod.message;
470         struct ldb_request *search_req;
471         struct ldb_message *remote_msg;
472         struct ldb_context *ldb;
473         struct map_context *ac;
474         int ret;
475
476         ldb = ldb_module_get_ctx(module);
477
478         /* Do not manipulate our control entries */
479         if (ldb_dn_is_special(msg->dn)) {
480                 return ldb_next_request(module, req);
481         }
482
483         /* No mapping requested (perhaps no DN mapping specified), skip to next module */
484         if (!ldb_dn_check_local(module, msg->dn)) {
485                 return ldb_next_request(module, req);
486         }
487
488         /* No mapping needed, skip to next module */
489         /* TODO: What if the remote part exists, the local doesn't,
490          *       and this request wants to modify local data and thus
491          *       add the local record? */
492         if (!ldb_msg_check_remote(module, msg)) {
493                 return LDB_ERR_OPERATIONS_ERROR;
494         }
495
496         /* Prepare context and handle */
497         ac = map_init_context(module, req);
498         if (ac == NULL) {
499                 return LDB_ERR_OPERATIONS_ERROR;
500         }
501
502         /* Prepare the local message */
503         ac->local_msg = ldb_msg_new(ac);
504         if (ac->local_msg == NULL) {
505                 map_oom(module);
506                 return LDB_ERR_OPERATIONS_ERROR;
507         }
508         ac->local_msg->dn = msg->dn;
509
510         /* Prepare the remote message */
511         remote_msg = ldb_msg_new(ac->remote_req);
512         if (remote_msg == NULL) {
513                 map_oom(module);
514                 return LDB_ERR_OPERATIONS_ERROR;
515         }
516         remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
517
518         /* Split local from remote message */
519         ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
520
521         /* Prepare the remote operation */
522         ret = ldb_build_mod_req(&ac->remote_req, ldb,
523                                 ac, remote_msg,
524                                 req->controls,
525                                 ac, map_op_remote_callback,
526                                 req);
527         LDB_REQ_SET_LOCATION(ac->remote_req);
528         if (ret != LDB_SUCCESS) {
529                 return LDB_ERR_OPERATIONS_ERROR;
530         }
531
532         if ((ac->local_msg->num_elements == 0) ||
533             ( ! map_check_local_db(ac->module))) {
534                 /* No local data or db, just run the remote request */
535                 return ldb_next_remote_request(ac->module, ac->remote_req);
536         }
537
538         /* prepare the search operation */
539         ret = map_search_self_req(&search_req, ac, msg->dn);
540         if (ret != LDB_SUCCESS) {
541                 return LDB_ERR_OPERATIONS_ERROR;
542         }
543
544         return ldb_next_request(module, search_req);
545 }
546
547 /* Modify the local record. */
548 static int map_modify_do_local(struct map_context *ac)
549 {
550         struct ldb_request *local_req;
551         struct ldb_context *ldb;
552         int ret;
553
554         ldb = ldb_module_get_ctx(ac->module);
555
556         if (ac->local_dn == NULL) {
557                 /* No local record present, add it instead */
558                 /* Add local 'IS_MAPPED' */
559                 /* TODO: use GUIDs here instead */
560                 if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED,
561                                         LDB_FLAG_MOD_ADD, NULL) != 0) {
562                         return LDB_ERR_OPERATIONS_ERROR;
563                 }
564                 ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED,
565                                                 ac->remote_req->op.mod.message->dn);
566                 if (ret != 0) {
567                         return LDB_ERR_OPERATIONS_ERROR;
568                 }
569
570                 /* Prepare the local operation */
571                 ret = ldb_build_add_req(&local_req, ldb, ac,
572                                         ac->local_msg,
573                                         ac->req->controls,
574                                         ac,
575                                         map_op_local_callback,
576                                         ac->req);
577                 LDB_REQ_SET_LOCATION(local_req);
578                 if (ret != LDB_SUCCESS) {
579                         return LDB_ERR_OPERATIONS_ERROR;
580                 }
581         } else {
582                 /* Prepare the local operation */
583                 ret = ldb_build_mod_req(&local_req, ldb, ac,
584                                         ac->local_msg,
585                                         ac->req->controls,
586                                         ac,
587                                         map_op_local_callback,
588                                         ac->req);
589                 LDB_REQ_SET_LOCATION(local_req);
590                 if (ret != LDB_SUCCESS) {
591                         return LDB_ERR_OPERATIONS_ERROR;
592                 }
593         }
594
595         return ldb_next_request(ac->module, local_req);
596 }
597
598 /*****************************************************************************
599  * DELETE operations
600 *****************************************************************************/
601
602 /* Delete a record. */
603 int map_delete(struct ldb_module *module, struct ldb_request *req)
604 {
605         struct ldb_request *search_req;
606         struct ldb_context *ldb;
607         struct map_context *ac;
608         int ret;
609
610         ldb = ldb_module_get_ctx(module);
611
612         /* Do not manipulate our control entries */
613         if (ldb_dn_is_special(req->op.del.dn)) {
614                 return ldb_next_request(module, req);
615         }
616
617         /* No mapping requested (perhaps no DN mapping specified).
618          * Skip to next module */
619         if (!ldb_dn_check_local(module, req->op.del.dn)) {
620                 return ldb_next_request(module, req);
621         }
622
623         /* Prepare context and handle */
624         ac = map_init_context(module, req);
625         if (ac == NULL) {
626                 return LDB_ERR_OPERATIONS_ERROR;
627         }
628
629         /* Prepare the remote operation */
630         ret = ldb_build_del_req(&ac->remote_req, ldb, ac,
631                                    ldb_dn_map_local(module, ac, req->op.del.dn),
632                                    req->controls,
633                                    ac,
634                                    map_op_remote_callback,
635                                    req);
636         LDB_REQ_SET_LOCATION(ac->remote_req);
637         if (ret != LDB_SUCCESS) {
638                 return LDB_ERR_OPERATIONS_ERROR;
639         }
640
641         /* No local db, just run the remote request */
642         if (!map_check_local_db(ac->module)) {
643                 /* Do the remote request. */
644                 return ldb_next_remote_request(ac->module, ac->remote_req);
645         }
646
647         /* Prepare the search operation */
648         ret = map_search_self_req(&search_req, ac, req->op.del.dn);
649         if (ret != LDB_SUCCESS) {
650                 map_oom(module);
651                 return LDB_ERR_OPERATIONS_ERROR;
652         }
653
654         return ldb_next_request(module, search_req);
655 }
656
657 /* Delete the local record. */
658 static int map_delete_do_local(struct map_context *ac)
659 {
660         struct ldb_request *local_req;
661         struct ldb_context *ldb;
662         int ret;
663
664         ldb = ldb_module_get_ctx(ac->module);
665
666         /* No local record, continue remotely */
667         if (ac->local_dn == NULL) {
668                 /* Do the remote request. */
669                 return ldb_next_remote_request(ac->module, ac->remote_req);
670         }
671
672         /* Prepare the local operation */
673         ret = ldb_build_del_req(&local_req, ldb, ac,
674                                    ac->req->op.del.dn,
675                                    ac->req->controls,
676                                    ac,
677                                    map_op_local_callback,
678                                    ac->req);
679         LDB_REQ_SET_LOCATION(local_req);
680         if (ret != LDB_SUCCESS) {
681                 return LDB_ERR_OPERATIONS_ERROR;
682         }
683         return ldb_next_request(ac->module, local_req);
684 }
685
686 /*****************************************************************************
687  * RENAME operations
688 *****************************************************************************/
689
690 /* Rename a record. */
691 int map_rename(struct ldb_module *module, struct ldb_request *req)
692 {
693         struct ldb_request *search_req;
694         struct ldb_context *ldb;
695         struct map_context *ac;
696         int ret;
697
698         ldb = ldb_module_get_ctx(module);
699
700         /* Do not manipulate our control entries */
701         if (ldb_dn_is_special(req->op.rename.olddn)) {
702                 return ldb_next_request(module, req);
703         }
704
705         /* No mapping requested (perhaps no DN mapping specified).
706          * Skip to next module */
707         if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
708             (!ldb_dn_check_local(module, req->op.rename.newdn))) {
709                 return ldb_next_request(module, req);
710         }
711
712         /* Rename into/out of the mapped partition requested, bail out */
713         if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
714             !ldb_dn_check_local(module, req->op.rename.newdn)) {
715                 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
716         }
717
718         /* Prepare context and handle */
719         ac = map_init_context(module, req);
720         if (ac == NULL) {
721                 return LDB_ERR_OPERATIONS_ERROR;
722         }
723
724         /* Prepare the remote operation */
725         ret = ldb_build_rename_req(&ac->remote_req, ldb, ac,
726                                    ldb_dn_map_local(module, ac, req->op.rename.olddn),
727                                    ldb_dn_map_local(module, ac, req->op.rename.newdn),
728                                    req->controls,
729                                    ac, map_op_remote_callback,
730                                    req);
731         LDB_REQ_SET_LOCATION(ac->remote_req);
732         if (ret != LDB_SUCCESS) {
733                 return LDB_ERR_OPERATIONS_ERROR;
734         }
735
736         /* No local db, just run the remote request */
737         if (!map_check_local_db(ac->module)) {
738                 /* Do the remote request. */
739                 return ldb_next_remote_request(ac->module, ac->remote_req);
740         }
741
742         /* Prepare the search operation */
743         ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
744         if (ret != LDB_SUCCESS) {
745                 map_oom(module);
746                 return LDB_ERR_OPERATIONS_ERROR;
747         }
748
749         return ldb_next_request(module, search_req);
750 }
751
752 /* Rename the local record. */
753 static int map_rename_do_local(struct map_context *ac)
754 {
755         struct ldb_request *local_req;
756         struct ldb_context *ldb;
757         int ret;
758
759         ldb = ldb_module_get_ctx(ac->module);
760
761         /* No local record, continue remotely */
762         if (ac->local_dn == NULL) {
763                 /* Do the remote request. */
764                 return ldb_next_remote_request(ac->module, ac->remote_req);
765         }
766
767         /* Prepare the local operation */
768         ret = ldb_build_rename_req(&local_req, ldb, ac,
769                                    ac->req->op.rename.olddn,
770                                    ac->req->op.rename.newdn,
771                                    ac->req->controls,
772                                    ac,
773                                    map_rename_local_callback,
774                                    ac->req);
775         LDB_REQ_SET_LOCATION(local_req);
776         if (ret != LDB_SUCCESS) {
777                 return LDB_ERR_OPERATIONS_ERROR;
778         }
779
780         return ldb_next_request(ac->module, local_req);
781 }
782
783 static int map_rename_local_callback(struct ldb_request *req,
784                                      struct ldb_reply *ares)
785 {
786         struct ldb_context *ldb;
787         struct map_context *ac;
788         int ret;
789
790         ac = talloc_get_type(req->context, struct map_context);
791         ldb = ldb_module_get_ctx(ac->module);
792
793         if (!ares) {
794                 return ldb_module_done(ac->req, NULL, NULL,
795                                         LDB_ERR_OPERATIONS_ERROR);
796         }
797         if (ares->error != LDB_SUCCESS) {
798                 return ldb_module_done(ac->req, ares->controls,
799                                         ares->response, ares->error);
800         }
801
802         if (ares->type != LDB_REPLY_DONE) {
803                 ldb_set_errstring(ldb, "Invalid reply type!");
804                 return ldb_module_done(ac->req, NULL, NULL,
805                                         LDB_ERR_OPERATIONS_ERROR);
806         }
807
808         /* proceed with next step */
809         ret = map_rename_do_fixup(ac);
810         if (ret != LDB_SUCCESS) {
811                 return ldb_module_done(ac->req, NULL, NULL,
812                                         LDB_ERR_OPERATIONS_ERROR);
813         }
814
815         return LDB_SUCCESS;
816 }
817
818 /* Update the local 'IS_MAPPED' attribute. */
819 static int map_rename_do_fixup(struct map_context *ac)
820 {
821         struct ldb_request *local_req;
822
823         /* Prepare the fixup operation */
824         /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
825         local_req = map_build_fixup_req(ac,
826                                         ac->req->op.rename.newdn,
827                                         ac->remote_req->op.rename.newdn,
828                                         ac,
829                                         map_op_local_callback);
830         if (local_req == NULL) {
831                 return LDB_ERR_OPERATIONS_ERROR;
832         }
833
834         return ldb_next_request(ac->module, local_req);
835 }