r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[sharpe/samba-autobuild/.git] / source3 / lib / ldb / modules / 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
7    * NOTICE: this module is NOT released under the GNU LGPL license as
8    * other ldb code. This module is release under the GNU GPL v2 or
9    * later license.
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program 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
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "ldb/include/includes.h"
27
28 #include "ldb/modules/ldb_map.h"
29 #include "ldb/modules/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         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
72         /* Unknown attribute: ignore */
73         if (map == NULL) {
74                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
75                           "Not mapping attribute '%s': no mapping found\n",
76                           old->name);
77                 goto local;
78         }
79
80         switch (map->type) {
81         case MAP_IGNORE:
82                 goto local;
83
84         case MAP_CONVERT:
85                 if (map->u.convert.convert_local == NULL) {
86                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
87                                   "Not mapping attribute '%s': "
88                                   "'convert_local' not set\n",
89                                   map->local_name);
90                         goto local;
91                 }
92                 /* fall through */
93         case MAP_KEEP:
94         case MAP_RENAME:
95                 el = ldb_msg_el_map_local(module, remote, map, old);
96                 break;
97
98         case MAP_GENERATE:
99                 if (map->u.generate.generate_remote == NULL) {
100                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
101                                   "Not mapping attribute '%s': "
102                                   "'generate_remote' not set\n",
103                                   map->local_name);
104                         goto local;
105                 }
106
107                 /* TODO: if this attr requires context:
108                  *       make sure all context attrs are mappable (in 'names')
109                  *       make sure all context attrs have already been mapped?
110                  *       maybe postpone generation until they have been mapped?
111                  */
112
113                 map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
114                 return 0;
115         }
116
117         if (el == NULL) {
118                 return -1;
119         }
120
121         return ldb_msg_add(remote, el, old->flags);
122
123 local:
124         el = talloc(local, struct ldb_message_element);
125         if (el == NULL) {
126                 map_oom(module);
127                 return -1;
128         }
129
130         *el = *old;                     /* copy the old element */
131
132         return ldb_msg_add(local, el, old->flags);
133 }
134
135 /* Mapping messages
136  * ================ */
137
138 /* Check whether a message will be (partially) mapped into the remote partition. */
139 static BOOL ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
140 {
141         const struct ldb_map_context *data = map_get_context(module);
142         BOOL ret;
143         int i;
144
145         for (i = 0; i < msg->num_elements; i++) {
146                 ret = map_attr_check_remote(data, msg->elements[i].name);
147                 if (ret) {
148                         return ret;
149                 }
150         }
151
152         return False;
153 }
154
155 /* Split message elements that stay in the local partition from those
156  * that are mapped into the remote partition. */
157 static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
158 {
159         /* const char * const names[]; */
160         int i, ret;
161
162         for (i = 0; i < msg->num_elements; i++) {
163                 /* Skip 'IS_MAPPED' */
164                 if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
165                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
166                                   "Skipping attribute '%s'\n",
167                                   msg->elements[i].name);
168                         continue;
169                 }
170
171                 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
172                 if (ret) {
173                         return ret;
174                 }
175         }
176
177         return 0;
178 }
179
180
181 /* Inbound requests: add, modify, rename, delete
182  * ============================================= */
183
184 /* Add the remote record. */
185 int map_add_do_remote(struct ldb_handle *handle)
186 {
187         struct map_context *ac;
188
189         ac = talloc_get_type(handle->private_data, struct map_context);
190
191         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
192
193         ac->step = MAP_ADD_REMOTE;
194
195         handle->state = LDB_ASYNC_INIT;
196         handle->status = LDB_SUCCESS;
197
198         return ldb_next_remote_request(ac->module, ac->remote_req);
199 }
200
201 /* Add the local record. */
202 int map_add_do_local(struct ldb_handle *handle)
203 {
204         struct map_context *ac;
205
206         ac = talloc_get_type(handle->private_data, struct map_context);
207
208         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
209
210         ac->step = MAP_ADD_LOCAL;
211
212         handle->state = LDB_ASYNC_INIT;
213         handle->status = LDB_SUCCESS;
214
215         return ldb_next_request(ac->module, ac->local_req);
216 }
217
218 /* Add a record. */
219 int map_add(struct ldb_module *module, struct ldb_request *req)
220 {
221         const struct ldb_message *msg = req->op.add.message;
222         struct ldb_handle *h;
223         struct map_context *ac;
224         struct ldb_message *local, *remote;
225         const char *dn;
226
227         /* Do not manipulate our control entries */
228         if (ldb_dn_is_special(msg->dn)) {
229                 return ldb_next_request(module, req);
230         }
231
232         /* No mapping requested (perhaps no DN mapping specified), skip to next module */
233         if (!ldb_dn_check_local(module, msg->dn)) {
234                 return ldb_next_request(module, req);
235         }
236
237         /* No mapping needed, fail */
238         if (!ldb_msg_check_remote(module, msg)) {
239                 return LDB_ERR_OPERATIONS_ERROR;
240         }
241
242         /* Prepare context and handle */
243         h = map_init_handle(req, module);
244         if (h == NULL) {
245                 return LDB_ERR_OPERATIONS_ERROR;
246         }
247         ac = talloc_get_type(h->private_data, struct map_context);
248
249         /* Prepare the local operation */
250         ac->local_req = talloc(ac, struct ldb_request);
251         if (ac->local_req == NULL) {
252                 goto oom;
253         }
254
255         *(ac->local_req) = *req;        /* copy the request */
256
257         ac->local_req->context = NULL;
258         ac->local_req->callback = NULL;
259
260         /* Prepare the remote operation */
261         ac->remote_req = talloc(ac, struct ldb_request);
262         if (ac->remote_req == NULL) {
263                 goto oom;
264         }
265
266         *(ac->remote_req) = *req;       /* copy the request */
267
268         ac->remote_req->context = NULL;
269         ac->remote_req->callback = NULL;
270
271         /* Prepare the local message */
272         local = ldb_msg_new(ac->local_req);
273         if (local == NULL) {
274                 goto oom;
275         }
276         local->dn = msg->dn;
277
278         /* Prepare the remote message */
279         remote = ldb_msg_new(ac->remote_req);
280         if (remote == NULL) {
281                 goto oom;
282         }
283         remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
284
285         /* Split local from remote message */
286         ldb_msg_partition(module, local, remote, msg);
287         ac->local_req->op.add.message = local;
288         ac->remote_req->op.add.message = remote;
289
290         if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
291                 /* No local data or db, just run the remote request */
292                 talloc_free(ac->local_req);
293                 req->handle = h;        /* return our own handle to deal with this call */
294                 return map_add_do_remote(h);
295         }
296
297         /* Store remote DN in 'IS_MAPPED' */
298         /* TODO: use GUIDs here instead */
299         dn = ldb_dn_linearize(local, remote->dn);
300         if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) {
301                 goto failed;
302         }
303
304         req->handle = h;                /* return our own handle to deal with this call */
305         return map_add_do_local(h);
306
307 oom:
308         map_oom(module);
309 failed:
310         talloc_free(h);
311         return LDB_ERR_OPERATIONS_ERROR;
312 }
313
314 /* Modify the remote record. */
315 int map_modify_do_remote(struct ldb_handle *handle)
316 {
317         struct map_context *ac;
318
319         ac = talloc_get_type(handle->private_data, struct map_context);
320
321         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
322
323         ac->step = MAP_MODIFY_REMOTE;
324
325         handle->state = LDB_ASYNC_INIT;
326         handle->status = LDB_SUCCESS;
327
328         return ldb_next_remote_request(ac->module, ac->remote_req);
329 }
330
331 /* Modify the local record. */
332 int map_modify_do_local(struct ldb_handle *handle)
333 {
334         struct map_context *ac;
335         struct ldb_message *msg;
336         char *dn;
337
338         ac = talloc_get_type(handle->private_data, struct map_context);
339
340         if (ac->local_dn == NULL) {
341                 /* No local record present, add it instead */
342                 msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message);
343
344                 /* Add local 'IS_MAPPED' */
345                 /* TODO: use GUIDs here instead */
346                 dn = ldb_dn_linearize(msg, ac->remote_req->op.mod.message->dn);
347                 if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) {
348                         return LDB_ERR_OPERATIONS_ERROR;
349                 }
350                 if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
351                         return LDB_ERR_OPERATIONS_ERROR;
352                 }
353
354                 /* Turn request into 'add' */
355                 ac->local_req->operation = LDB_ADD;
356                 ac->local_req->op.add.message = msg;
357                 /* TODO: Could I just leave msg in there?  I think so,
358                  *       but it looks clearer this way. */
359         }
360
361         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
362
363         ac->step = MAP_MODIFY_LOCAL;
364
365         handle->state = LDB_ASYNC_INIT;
366         handle->status = LDB_SUCCESS;
367
368         return ldb_next_request(ac->module, ac->local_req);
369 }
370
371 /* Modify a record. */
372 int map_modify(struct ldb_module *module, struct ldb_request *req)
373 {
374         const struct ldb_message *msg = req->op.mod.message;
375         struct ldb_handle *h;
376         struct map_context *ac;
377         struct ldb_message *local, *remote;
378
379         /* Do not manipulate our control entries */
380         if (ldb_dn_is_special(msg->dn)) {
381                 return ldb_next_request(module, req);
382         }
383
384         /* No mapping requested (perhaps no DN mapping specified), skip to next module */
385         if (!ldb_dn_check_local(module, msg->dn)) {
386                 return ldb_next_request(module, req);
387         }
388
389         /* No mapping needed, skip to next module */
390         /* TODO: What if the remote part exists, the local doesn't,
391          *       and this request wants to modify local data and thus
392          *       add the local record? */
393         if (!ldb_msg_check_remote(module, msg)) {
394                 return LDB_ERR_OPERATIONS_ERROR;
395         }
396
397         /* Prepare context and handle */
398         h = map_init_handle(req, module);
399         if (h == NULL) {
400                 return LDB_ERR_OPERATIONS_ERROR;
401         }
402         ac = talloc_get_type(h->private_data, struct map_context);
403
404         /* Prepare the local operation */
405         ac->local_req = talloc(ac, struct ldb_request);
406         if (ac->local_req == NULL) {
407                 goto oom;
408         }
409
410         *(ac->local_req) = *req;        /* copy the request */
411
412         ac->local_req->context = NULL;
413         ac->local_req->callback = NULL;
414
415         /* Prepare the remote operation */
416         ac->remote_req = talloc(ac, struct ldb_request);
417         if (ac->remote_req == NULL) {
418                 goto oom;
419         }
420
421         *(ac->remote_req) = *req;       /* copy the request */
422
423         ac->remote_req->context = NULL;
424         ac->remote_req->callback = NULL;
425
426         /* Prepare the local message */
427         local = ldb_msg_new(ac->local_req);
428         if (local == NULL) {
429                 goto oom;
430         }
431         local->dn = msg->dn;
432
433         /* Prepare the remote message */
434         remote = ldb_msg_new(ac->remote_req);
435         if (remote == NULL) {
436                 goto oom;
437         }
438         remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
439
440         /* Split local from remote message */
441         ldb_msg_partition(module, local, remote, msg);
442         ac->local_req->op.mod.message = local;
443         ac->remote_req->op.mod.message = remote;
444
445         if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
446                 /* No local data or db, just run the remote request */
447                 talloc_free(ac->local_req);
448                 req->handle = h;        /* return our own handle to deal with this call */
449                 return map_modify_do_remote(h);
450         }
451
452         /* prepare the search operation */
453         ac->search_req = map_search_self_req(ac, msg->dn);
454         if (ac->search_req == NULL) {
455                 goto failed;
456         }
457
458         ac->step = MAP_SEARCH_SELF_MODIFY;
459
460         req->handle = h;                /* return our own handle to deal with this call */
461         return ldb_next_request(module, ac->search_req);
462
463 oom:
464         map_oom(module);
465 failed:
466         talloc_free(h);
467         return LDB_ERR_OPERATIONS_ERROR;
468 }
469
470 /* Delete the remote record. */
471 int map_delete_do_remote(struct ldb_handle *handle)
472 {
473         struct map_context *ac;
474
475         ac = talloc_get_type(handle->private_data, struct map_context);
476
477         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
478
479         ac->step = MAP_DELETE_REMOTE;
480
481         handle->state = LDB_ASYNC_INIT;
482         handle->status = LDB_SUCCESS;
483
484         return ldb_next_remote_request(ac->module, ac->remote_req);
485 }
486
487 /* Delete the local record. */
488 int map_delete_do_local(struct ldb_handle *handle)
489 {
490         struct map_context *ac;
491
492         ac = talloc_get_type(handle->private_data, struct map_context);
493
494         /* No local record, continue remotely */
495         if (ac->local_dn == NULL) {
496                 return map_delete_do_remote(handle);
497         }
498
499         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
500
501         ac->step = MAP_DELETE_LOCAL;
502
503         handle->state = LDB_ASYNC_INIT;
504         handle->status = LDB_SUCCESS;
505
506         return ldb_next_request(ac->module, ac->local_req);
507 }
508
509 /* Delete a record. */
510 int map_delete(struct ldb_module *module, struct ldb_request *req)
511 {
512         struct ldb_handle *h;
513         struct map_context *ac;
514
515         /* Do not manipulate our control entries */
516         if (ldb_dn_is_special(req->op.del.dn)) {
517                 return ldb_next_request(module, req);
518         }
519
520         /* No mapping requested (perhaps no DN mapping specified), skip to next module */
521         if (!ldb_dn_check_local(module, req->op.del.dn)) {
522                 return ldb_next_request(module, req);
523         }
524
525         /* Prepare context and handle */
526         h = map_init_handle(req, module);
527         if (h == NULL) {
528                 return LDB_ERR_OPERATIONS_ERROR;
529         }
530         ac = talloc_get_type(h->private_data, struct map_context);
531
532         /* Prepare the local operation */
533         ac->local_req = talloc(ac, struct ldb_request);
534         if (ac->local_req == NULL) {
535                 goto oom;
536         }
537
538         *(ac->local_req) = *req;        /* copy the request */
539         ac->local_req->op.del.dn = req->op.del.dn;
540
541         ac->local_req->context = NULL;
542         ac->local_req->callback = NULL;
543
544         /* Prepare the remote operation */
545         ac->remote_req = talloc(ac, struct ldb_request);
546         if (ac->remote_req == NULL) {
547                 goto oom;
548         }
549
550         *(ac->remote_req) = *req;       /* copy the request */
551         ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn);
552
553         /* No local db, just run the remote request */
554         if (!map_check_local_db(ac->module)) {
555                 req->handle = h;        /* return our own handle to deal with this call */
556                 return map_delete_do_remote(h);
557         }
558
559         ac->remote_req->context = NULL;
560         ac->remote_req->callback = NULL;
561
562         /* Prepare the search operation */
563         ac->search_req = map_search_self_req(ac, req->op.del.dn);
564         if (ac->search_req == NULL) {
565                 goto failed;
566         }
567
568         req->handle = h;                /* return our own handle to deal with this call */
569
570         ac->step = MAP_SEARCH_SELF_DELETE;
571
572         return ldb_next_request(module, ac->search_req);
573
574 oom:
575         map_oom(module);
576 failed:
577         talloc_free(h);
578         return LDB_ERR_OPERATIONS_ERROR;
579 }
580
581 /* Rename the remote record. */
582 int map_rename_do_remote(struct ldb_handle *handle)
583 {
584         struct map_context *ac;
585
586         ac = talloc_get_type(handle->private_data, struct map_context);
587
588         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
589
590         ac->step = MAP_RENAME_REMOTE;
591
592         handle->state = LDB_ASYNC_INIT;
593         handle->status = LDB_SUCCESS;
594
595         return ldb_next_remote_request(ac->module, ac->remote_req);
596 }
597
598 /* Update the local 'IS_MAPPED' attribute. */
599 int map_rename_do_fixup(struct ldb_handle *handle)
600 {
601         struct map_context *ac;
602
603         ac = talloc_get_type(handle->private_data, struct map_context);
604
605         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
606
607         ac->step = MAP_RENAME_FIXUP;
608
609         handle->state = LDB_ASYNC_INIT;
610         handle->status = LDB_SUCCESS;
611
612         return ldb_next_request(ac->module, ac->down_req);
613 }
614
615 /* Rename the local record. */
616 int map_rename_do_local(struct ldb_handle *handle)
617 {
618         struct map_context *ac;
619
620         ac = talloc_get_type(handle->private_data, struct map_context);
621
622         /* No local record, continue remotely */
623         if (ac->local_dn == NULL) {
624                 return map_rename_do_remote(handle);
625         }
626
627         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
628
629         ac->step = MAP_RENAME_LOCAL;
630
631         handle->state = LDB_ASYNC_INIT;
632         handle->status = LDB_SUCCESS;
633
634         return ldb_next_request(ac->module, ac->local_req);
635 }
636
637 /* Rename a record. */
638 int map_rename(struct ldb_module *module, struct ldb_request *req)
639 {
640         struct ldb_handle *h;
641         struct map_context *ac;
642
643         /* Do not manipulate our control entries */
644         if (ldb_dn_is_special(req->op.rename.olddn)) {
645                 return ldb_next_request(module, req);
646         }
647
648         /* No mapping requested (perhaps no DN mapping specified), skip to next module */
649         if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
650             (!ldb_dn_check_local(module, req->op.rename.newdn))) {
651                 return ldb_next_request(module, req);
652         }
653
654         /* Rename into/out of the mapped partition requested, bail out */
655         if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
656             !ldb_dn_check_local(module, req->op.rename.newdn)) {
657                 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
658         }
659
660         /* Prepare context and handle */
661         h = map_init_handle(req, module);
662         if (h == NULL) {
663                 return LDB_ERR_OPERATIONS_ERROR;
664         }
665         ac = talloc_get_type(h->private_data, struct map_context);
666
667         /* Prepare the local operation */
668         ac->local_req = talloc(ac, struct ldb_request);
669         if (ac->local_req == NULL) {
670                 goto oom;
671         }
672
673         *(ac->local_req) = *req;        /* copy the request */
674         ac->local_req->op.rename.olddn = req->op.rename.olddn;
675         ac->local_req->op.rename.newdn = req->op.rename.newdn;
676
677         ac->local_req->context = NULL;
678         ac->local_req->callback = NULL;
679
680         /* Prepare the remote operation */
681         ac->remote_req = talloc(ac, struct ldb_request);
682         if (ac->remote_req == NULL) {
683                 goto oom;
684         }
685
686         *(ac->remote_req) = *req;       /* copy the request */
687         ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn);
688         ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn);
689
690         ac->remote_req->context = NULL;
691         ac->remote_req->callback = NULL;
692
693         /* No local db, just run the remote request */
694         if (!map_check_local_db(ac->module)) {
695                 req->handle = h;        /* return our own handle to deal with this call */
696                 return map_rename_do_remote(h);
697         }
698
699         /* Prepare the fixup operation */
700         /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
701         ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn);
702         if (ac->down_req == NULL) {
703                 goto failed;
704         }
705
706         /* Prepare the search operation */
707         ac->search_req = map_search_self_req(ac, req->op.rename.olddn);
708         if (ac->search_req == NULL) {
709                 goto failed;
710         }
711
712         req->handle = h;                /* return our own handle to deal with this call */
713
714         ac->step = MAP_SEARCH_SELF_RENAME;
715
716         return ldb_next_request(module, ac->search_req);
717
718 oom:
719         map_oom(module);
720 failed:
721         talloc_free(h);
722         return LDB_ERR_OPERATIONS_ERROR;
723 }