r25068: Older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for every opcode on the
[Samba.git] / source / lib / ldb / modules / ldb_map_inbound.c
blob38454b2b1168c36fe4173f2f256a99cc6ea572fc
1 /*
2 ldb database mapping module
4 Copyright (C) Jelmer Vernooij 2005
5 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
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.
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 2 of the License, or
14 (at your option) any later version.
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.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "includes.h"
27 #include "ldb/include/includes.h"
29 #include "ldb/modules/ldb_map.h"
30 #include "ldb/modules/ldb_map_private.h"
33 /* Mapping message elements
34 * ======================== */
36 /* Map a message element into the remote partition. */
37 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)
39 struct ldb_message_element *el;
40 int i;
42 el = talloc_zero(mem_ctx, struct ldb_message_element);
43 if (el == NULL) {
44 map_oom(module);
45 return NULL;
48 el->num_values = old->num_values;
49 el->values = talloc_array(el, struct ldb_val, el->num_values);
50 if (el->values == NULL) {
51 talloc_free(el);
52 map_oom(module);
53 return NULL;
56 el->name = map_attr_map_local(el, map, old->name);
58 for (i = 0; i < el->num_values; i++) {
59 el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
62 return el;
65 /* Add a message element either to a local or to a remote message,
66 * depending on whether it goes into the local or remote partition. */
67 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)
69 const struct ldb_map_context *data = map_get_context(module);
70 const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
71 struct ldb_message_element *el=NULL;
73 /* Unknown attribute: ignore */
74 if (map == NULL) {
75 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
76 "Not mapping attribute '%s': no mapping found\n",
77 old->name);
78 goto local;
81 switch (map->type) {
82 case MAP_IGNORE:
83 goto local;
85 case MAP_CONVERT:
86 if (map->u.convert.convert_local == NULL) {
87 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
88 "Not mapping attribute '%s': "
89 "'convert_local' not set\n",
90 map->local_name);
91 goto local;
93 /* fall through */
94 case MAP_KEEP:
95 case MAP_RENAME:
96 el = ldb_msg_el_map_local(module, remote, map, old);
97 break;
99 case MAP_GENERATE:
100 if (map->u.generate.generate_remote == NULL) {
101 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
102 "Not mapping attribute '%s': "
103 "'generate_remote' not set\n",
104 map->local_name);
105 goto local;
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?
114 map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
115 return 0;
118 if (el == NULL) {
119 return -1;
122 return ldb_msg_add(remote, el, old->flags);
124 local:
125 el = talloc(local, struct ldb_message_element);
126 if (el == NULL) {
127 map_oom(module);
128 return -1;
131 *el = *old; /* copy the old element */
133 return ldb_msg_add(local, el, old->flags);
136 /* Mapping messages
137 * ================ */
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)
142 const struct ldb_map_context *data = map_get_context(module);
143 BOOL ret;
144 int i;
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;
153 return False;
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)
160 /* const char * const names[]; */
161 int i, ret;
163 for (i = 0; i < msg->num_elements; i++) {
164 /* Skip 'IS_MAPPED' */
165 if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
166 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
167 "Skipping attribute '%s'\n",
168 msg->elements[i].name);
169 continue;
172 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
173 if (ret) {
174 return ret;
178 return 0;
182 /* Inbound requests: add, modify, rename, delete
183 * ============================================= */
185 /* Add the remote record. */
186 int map_add_do_remote(struct ldb_handle *handle)
188 struct map_context *ac;
190 ac = talloc_get_type(handle->private_data, struct map_context);
192 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
194 ac->step = MAP_ADD_REMOTE;
196 handle->state = LDB_ASYNC_INIT;
197 handle->status = LDB_SUCCESS;
199 return ldb_next_remote_request(ac->module, ac->remote_req);
202 /* Add the local record. */
203 int map_add_do_local(struct ldb_handle *handle)
205 struct map_context *ac;
207 ac = talloc_get_type(handle->private_data, struct map_context);
209 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
211 ac->step = MAP_ADD_LOCAL;
213 handle->state = LDB_ASYNC_INIT;
214 handle->status = LDB_SUCCESS;
216 return ldb_next_request(ac->module, ac->local_req);
219 /* Add a record. */
220 int map_add(struct ldb_module *module, struct ldb_request *req)
222 const struct ldb_message *msg = req->op.add.message;
223 struct ldb_handle *h;
224 struct map_context *ac;
225 struct ldb_message *local, *remote;
226 const char *dn;
228 /* Do not manipulate our control entries */
229 if (ldb_dn_is_special(msg->dn)) {
230 return ldb_next_request(module, req);
233 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
234 if (!ldb_dn_check_local(module, msg->dn)) {
235 return ldb_next_request(module, req);
238 /* No mapping needed, fail */
239 if (!ldb_msg_check_remote(module, msg)) {
240 return LDB_ERR_OPERATIONS_ERROR;
243 /* Prepare context and handle */
244 h = map_init_handle(req, module);
245 if (h == NULL) {
246 return LDB_ERR_OPERATIONS_ERROR;
248 ac = talloc_get_type(h->private_data, struct map_context);
250 /* Prepare the local operation */
251 ac->local_req = talloc(ac, struct ldb_request);
252 if (ac->local_req == NULL) {
253 goto oom;
256 *(ac->local_req) = *req; /* copy the request */
258 ac->local_req->context = NULL;
259 ac->local_req->callback = NULL;
261 /* Prepare the remote operation */
262 ac->remote_req = talloc(ac, struct ldb_request);
263 if (ac->remote_req == NULL) {
264 goto oom;
267 *(ac->remote_req) = *req; /* copy the request */
269 ac->remote_req->context = NULL;
270 ac->remote_req->callback = NULL;
272 /* Prepare the local message */
273 local = ldb_msg_new(ac->local_req);
274 if (local == NULL) {
275 goto oom;
277 local->dn = msg->dn;
279 /* Prepare the remote message */
280 remote = ldb_msg_new(ac->remote_req);
281 if (remote == NULL) {
282 goto oom;
284 remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
286 /* Split local from remote message */
287 ldb_msg_partition(module, local, remote, msg);
288 ac->local_req->op.add.message = local;
289 ac->remote_req->op.add.message = remote;
291 if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
292 /* No local data or db, just run the remote request */
293 talloc_free(ac->local_req);
294 req->handle = h; /* return our own handle to deal with this call */
295 return map_add_do_remote(h);
298 /* Store remote DN in 'IS_MAPPED' */
299 /* TODO: use GUIDs here instead */
300 dn = ldb_dn_linearize(local, remote->dn);
301 if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) {
302 goto failed;
305 req->handle = h; /* return our own handle to deal with this call */
306 return map_add_do_local(h);
308 oom:
309 map_oom(module);
310 failed:
311 talloc_free(h);
312 return LDB_ERR_OPERATIONS_ERROR;
315 /* Modify the remote record. */
316 int map_modify_do_remote(struct ldb_handle *handle)
318 struct map_context *ac;
320 ac = talloc_get_type(handle->private_data, struct map_context);
322 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
324 ac->step = MAP_MODIFY_REMOTE;
326 handle->state = LDB_ASYNC_INIT;
327 handle->status = LDB_SUCCESS;
329 return ldb_next_remote_request(ac->module, ac->remote_req);
332 /* Modify the local record. */
333 int map_modify_do_local(struct ldb_handle *handle)
335 struct map_context *ac;
336 struct ldb_message *msg;
337 char *dn;
339 ac = talloc_get_type(handle->private_data, struct map_context);
341 if (ac->local_dn == NULL) {
342 /* No local record present, add it instead */
343 msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message);
345 /* Add local 'IS_MAPPED' */
346 /* TODO: use GUIDs here instead */
347 dn = ldb_dn_linearize(msg, ac->remote_req->op.mod.message->dn);
348 if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) {
349 return LDB_ERR_OPERATIONS_ERROR;
351 if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
352 return LDB_ERR_OPERATIONS_ERROR;
355 /* Turn request into 'add' */
356 ac->local_req->operation = LDB_ADD;
357 ac->local_req->op.add.message = msg;
358 /* TODO: Could I just leave msg in there? I think so,
359 * but it looks clearer this way. */
362 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
364 ac->step = MAP_MODIFY_LOCAL;
366 handle->state = LDB_ASYNC_INIT;
367 handle->status = LDB_SUCCESS;
369 return ldb_next_request(ac->module, ac->local_req);
372 /* Modify a record. */
373 int map_modify(struct ldb_module *module, struct ldb_request *req)
375 const struct ldb_message *msg = req->op.mod.message;
376 struct ldb_handle *h;
377 struct map_context *ac;
378 struct ldb_message *local, *remote;
380 /* Do not manipulate our control entries */
381 if (ldb_dn_is_special(msg->dn)) {
382 return ldb_next_request(module, req);
385 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
386 if (!ldb_dn_check_local(module, msg->dn)) {
387 return ldb_next_request(module, req);
390 /* No mapping needed, skip to next module */
391 /* TODO: What if the remote part exists, the local doesn't,
392 * and this request wants to modify local data and thus
393 * add the local record? */
394 if (!ldb_msg_check_remote(module, msg)) {
395 return LDB_ERR_OPERATIONS_ERROR;
398 /* Prepare context and handle */
399 h = map_init_handle(req, module);
400 if (h == NULL) {
401 return LDB_ERR_OPERATIONS_ERROR;
403 ac = talloc_get_type(h->private_data, struct map_context);
405 /* Prepare the local operation */
406 ac->local_req = talloc(ac, struct ldb_request);
407 if (ac->local_req == NULL) {
408 goto oom;
411 *(ac->local_req) = *req; /* copy the request */
413 ac->local_req->context = NULL;
414 ac->local_req->callback = NULL;
416 /* Prepare the remote operation */
417 ac->remote_req = talloc(ac, struct ldb_request);
418 if (ac->remote_req == NULL) {
419 goto oom;
422 *(ac->remote_req) = *req; /* copy the request */
424 ac->remote_req->context = NULL;
425 ac->remote_req->callback = NULL;
427 /* Prepare the local message */
428 local = ldb_msg_new(ac->local_req);
429 if (local == NULL) {
430 goto oom;
432 local->dn = msg->dn;
434 /* Prepare the remote message */
435 remote = ldb_msg_new(ac->remote_req);
436 if (remote == NULL) {
437 goto oom;
439 remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
441 /* Split local from remote message */
442 ldb_msg_partition(module, local, remote, msg);
443 ac->local_req->op.mod.message = local;
444 ac->remote_req->op.mod.message = remote;
446 if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
447 /* No local data or db, just run the remote request */
448 talloc_free(ac->local_req);
449 req->handle = h; /* return our own handle to deal with this call */
450 return map_modify_do_remote(h);
453 /* prepare the search operation */
454 ac->search_req = map_search_self_req(ac, msg->dn);
455 if (ac->search_req == NULL) {
456 goto failed;
459 ac->step = MAP_SEARCH_SELF_MODIFY;
461 req->handle = h; /* return our own handle to deal with this call */
462 return ldb_next_request(module, ac->search_req);
464 oom:
465 map_oom(module);
466 failed:
467 talloc_free(h);
468 return LDB_ERR_OPERATIONS_ERROR;
471 /* Delete the remote record. */
472 int map_delete_do_remote(struct ldb_handle *handle)
474 struct map_context *ac;
476 ac = talloc_get_type(handle->private_data, struct map_context);
478 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
480 ac->step = MAP_DELETE_REMOTE;
482 handle->state = LDB_ASYNC_INIT;
483 handle->status = LDB_SUCCESS;
485 return ldb_next_remote_request(ac->module, ac->remote_req);
488 /* Delete the local record. */
489 int map_delete_do_local(struct ldb_handle *handle)
491 struct map_context *ac;
493 ac = talloc_get_type(handle->private_data, struct map_context);
495 /* No local record, continue remotely */
496 if (ac->local_dn == NULL) {
497 return map_delete_do_remote(handle);
500 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
502 ac->step = MAP_DELETE_LOCAL;
504 handle->state = LDB_ASYNC_INIT;
505 handle->status = LDB_SUCCESS;
507 return ldb_next_request(ac->module, ac->local_req);
510 /* Delete a record. */
511 int map_delete(struct ldb_module *module, struct ldb_request *req)
513 struct ldb_handle *h;
514 struct map_context *ac;
516 /* Do not manipulate our control entries */
517 if (ldb_dn_is_special(req->op.del.dn)) {
518 return ldb_next_request(module, req);
521 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
522 if (!ldb_dn_check_local(module, req->op.del.dn)) {
523 return ldb_next_request(module, req);
526 /* Prepare context and handle */
527 h = map_init_handle(req, module);
528 if (h == NULL) {
529 return LDB_ERR_OPERATIONS_ERROR;
531 ac = talloc_get_type(h->private_data, struct map_context);
533 /* Prepare the local operation */
534 ac->local_req = talloc(ac, struct ldb_request);
535 if (ac->local_req == NULL) {
536 goto oom;
539 *(ac->local_req) = *req; /* copy the request */
540 ac->local_req->op.del.dn = req->op.del.dn;
542 ac->local_req->context = NULL;
543 ac->local_req->callback = NULL;
545 /* Prepare the remote operation */
546 ac->remote_req = talloc(ac, struct ldb_request);
547 if (ac->remote_req == NULL) {
548 goto oom;
551 *(ac->remote_req) = *req; /* copy the request */
552 ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn);
554 /* No local db, just run the remote request */
555 if (!map_check_local_db(ac->module)) {
556 req->handle = h; /* return our own handle to deal with this call */
557 return map_delete_do_remote(h);
560 ac->remote_req->context = NULL;
561 ac->remote_req->callback = NULL;
563 /* Prepare the search operation */
564 ac->search_req = map_search_self_req(ac, req->op.del.dn);
565 if (ac->search_req == NULL) {
566 goto failed;
569 req->handle = h; /* return our own handle to deal with this call */
571 ac->step = MAP_SEARCH_SELF_DELETE;
573 return ldb_next_request(module, ac->search_req);
575 oom:
576 map_oom(module);
577 failed:
578 talloc_free(h);
579 return LDB_ERR_OPERATIONS_ERROR;
582 /* Rename the remote record. */
583 int map_rename_do_remote(struct ldb_handle *handle)
585 struct map_context *ac;
587 ac = talloc_get_type(handle->private_data, struct map_context);
589 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
591 ac->step = MAP_RENAME_REMOTE;
593 handle->state = LDB_ASYNC_INIT;
594 handle->status = LDB_SUCCESS;
596 return ldb_next_remote_request(ac->module, ac->remote_req);
599 /* Update the local 'IS_MAPPED' attribute. */
600 int map_rename_do_fixup(struct ldb_handle *handle)
602 struct map_context *ac;
604 ac = talloc_get_type(handle->private_data, struct map_context);
606 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
608 ac->step = MAP_RENAME_FIXUP;
610 handle->state = LDB_ASYNC_INIT;
611 handle->status = LDB_SUCCESS;
613 return ldb_next_request(ac->module, ac->down_req);
616 /* Rename the local record. */
617 int map_rename_do_local(struct ldb_handle *handle)
619 struct map_context *ac;
621 ac = talloc_get_type(handle->private_data, struct map_context);
623 /* No local record, continue remotely */
624 if (ac->local_dn == NULL) {
625 return map_rename_do_remote(handle);
628 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
630 ac->step = MAP_RENAME_LOCAL;
632 handle->state = LDB_ASYNC_INIT;
633 handle->status = LDB_SUCCESS;
635 return ldb_next_request(ac->module, ac->local_req);
638 /* Rename a record. */
639 int map_rename(struct ldb_module *module, struct ldb_request *req)
641 struct ldb_handle *h;
642 struct map_context *ac;
644 /* Do not manipulate our control entries */
645 if (ldb_dn_is_special(req->op.rename.olddn)) {
646 return ldb_next_request(module, req);
649 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
650 if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
651 (!ldb_dn_check_local(module, req->op.rename.newdn))) {
652 return ldb_next_request(module, req);
655 /* Rename into/out of the mapped partition requested, bail out */
656 if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
657 !ldb_dn_check_local(module, req->op.rename.newdn)) {
658 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
661 /* Prepare context and handle */
662 h = map_init_handle(req, module);
663 if (h == NULL) {
664 return LDB_ERR_OPERATIONS_ERROR;
666 ac = talloc_get_type(h->private_data, struct map_context);
668 /* Prepare the local operation */
669 ac->local_req = talloc(ac, struct ldb_request);
670 if (ac->local_req == NULL) {
671 goto oom;
674 *(ac->local_req) = *req; /* copy the request */
675 ac->local_req->op.rename.olddn = req->op.rename.olddn;
676 ac->local_req->op.rename.newdn = req->op.rename.newdn;
678 ac->local_req->context = NULL;
679 ac->local_req->callback = NULL;
681 /* Prepare the remote operation */
682 ac->remote_req = talloc(ac, struct ldb_request);
683 if (ac->remote_req == NULL) {
684 goto oom;
687 *(ac->remote_req) = *req; /* copy the request */
688 ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn);
689 ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn);
691 ac->remote_req->context = NULL;
692 ac->remote_req->callback = NULL;
694 /* No local db, just run the remote request */
695 if (!map_check_local_db(ac->module)) {
696 req->handle = h; /* return our own handle to deal with this call */
697 return map_rename_do_remote(h);
700 /* Prepare the fixup operation */
701 /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
702 ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn);
703 if (ac->down_req == NULL) {
704 goto failed;
707 /* Prepare the search operation */
708 ac->search_req = map_search_self_req(ac, req->op.rename.olddn);
709 if (ac->search_req == NULL) {
710 goto failed;
713 req->handle = h; /* return our own handle to deal with this call */
715 ac->step = MAP_SEARCH_SELF_RENAME;
717 return ldb_next_request(module, ac->search_req);
719 oom:
720 map_oom(module);
721 failed:
722 talloc_free(h);
723 return LDB_ERR_OPERATIONS_ERROR;