2 ldb database mapping module
4 Copyright (C) Jelmer Vernooij 2005
5 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6 Copyright (C) Simo Sorce <idra@samba.org> 2008
8 ** NOTE! The following LGPL license applies to the ldb
9 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
27 #include "ldb_includes.h"
30 #include "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;
42 el = talloc_zero(mem_ctx, struct ldb_message_element);
48 el->num_values = old->num_values;
49 el->values = talloc_array(el, struct ldb_val, el->num_values);
50 if (el->values == 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]);
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 */
75 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
76 "Not mapping attribute '%s': no mapping found\n",
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",
96 el = ldb_msg_el_map_local(module, remote, map, old);
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",
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);
122 return ldb_msg_add(remote, el, old->flags);
125 el = talloc(local, struct ldb_message_element);
131 *el = *old; /* copy the old element */
133 return ldb_msg_add(local, el, old->flags);
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);
146 for (i = 0; i < msg->num_elements; i++) {
147 ret = map_attr_check_remote(data, msg->elements[i].name);
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[]; */
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);
172 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
182 static int map_add_do_local(struct map_context *ac);
183 static int map_modify_do_local(struct map_context *ac);
184 static int map_delete_do_local(struct map_context *ac);
185 static int map_rename_do_local(struct map_context *ac);
186 static int map_rename_do_fixup(struct map_context *ac);
187 static int map_rename_local_callback(struct ldb_request *req,
188 struct ldb_reply *ares);
191 /*****************************************************************************
192 * COMMON INBOUND functions
193 *****************************************************************************/
195 /* Store the DN of a single search result in context. */
196 static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
198 struct map_context *ac;
201 ac = talloc_get_type(req->context, struct map_context);
204 return ldb_module_done(ac->req, NULL, NULL,
205 LDB_ERR_OPERATIONS_ERROR);
207 if (ares->error != LDB_SUCCESS) {
208 return ldb_module_done(ac->req, ares->controls,
209 ares->response, ares->error);
212 /* We are interested only in the single reply */
214 case LDB_REPLY_ENTRY:
215 /* We have already found a remote DN */
217 ldb_set_errstring(ac->module->ldb,
218 "Too many results!");
219 return ldb_module_done(ac->req, NULL, NULL,
220 LDB_ERR_OPERATIONS_ERROR);
224 ac->local_dn = talloc_steal(ac, ares->message->dn);
229 switch (ac->req->operation) {
231 ret = map_modify_do_local(ac);
234 ret = map_delete_do_local(ac);
237 ret = map_rename_do_local(ac);
240 /* if we get here we have definitely a problem */
241 ret = LDB_ERR_OPERATIONS_ERROR;
243 if (ret != LDB_SUCCESS) {
244 return ldb_module_done(ac->req, NULL, NULL,
245 LDB_ERR_OPERATIONS_ERROR);
249 /* ignore referrals */
257 /* Build a request to search the local record by its DN. */
258 static int map_search_self_req(struct ldb_request **req,
259 struct map_context *ac,
262 /* attrs[] is returned from this function in
263 * ac->search_req->op.search.attrs, so it must be static, as
264 * otherwise the compiler can put it on the stack */
265 static const char * const attrs[] = { IS_MAPPED, NULL };
266 struct ldb_parse_tree *tree;
268 /* Limit search to records with 'IS_MAPPED' present */
269 tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
272 return LDB_ERR_OPERATIONS_ERROR;
275 *req = map_search_base_req(ac, dn, attrs, tree,
276 ac, map_search_self_callback);
278 return LDB_ERR_OPERATIONS_ERROR;
284 static int map_op_local_callback(struct ldb_request *req,
285 struct ldb_reply *ares)
287 struct map_context *ac;
290 ac = talloc_get_type(req->context, struct map_context);
293 return ldb_module_done(ac->req, NULL, NULL,
294 LDB_ERR_OPERATIONS_ERROR);
296 if (ares->error != LDB_SUCCESS) {
297 return ldb_module_done(ac->req, ares->controls,
298 ares->response, ares->error);
301 if (ares->type != LDB_REPLY_DONE) {
302 ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
303 return ldb_module_done(ac->req, NULL, NULL,
304 LDB_ERR_OPERATIONS_ERROR);
307 /* Do the remote request. */
308 ret = ldb_next_remote_request(ac->module, ac->remote_req);
309 if (ret != LDB_SUCCESS) {
310 return ldb_module_done(ac->req, NULL, NULL,
311 LDB_ERR_OPERATIONS_ERROR);
317 static int map_op_remote_callback(struct ldb_request *req,
318 struct ldb_reply *ares)
320 struct map_context *ac;
322 ac = talloc_get_type(req->context, struct map_context);
325 return ldb_module_done(ac->req, NULL, NULL,
326 LDB_ERR_OPERATIONS_ERROR);
328 if (ares->error != LDB_SUCCESS) {
329 return ldb_module_done(ac->req, ares->controls,
330 ares->response, ares->error);
333 if (ares->type != LDB_REPLY_DONE) {
334 ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
335 return ldb_module_done(ac->req, NULL, NULL,
336 LDB_ERR_OPERATIONS_ERROR);
339 return ldb_module_done(ac->req, ares->controls,
340 ares->response, ares->error);
344 /*****************************************************************************
346 *****************************************************************************/
350 int map_add(struct ldb_module *module, struct ldb_request *req)
352 const struct ldb_message *msg = req->op.add.message;
353 struct map_context *ac;
354 struct ldb_message *remote_msg;
358 /* Do not manipulate our control entries */
359 if (ldb_dn_is_special(msg->dn)) {
360 return ldb_next_request(module, req);
363 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
364 if (!ldb_dn_check_local(module, msg->dn)) {
365 return ldb_next_request(module, req);
368 /* No mapping needed, fail */
369 if (!ldb_msg_check_remote(module, msg)) {
370 return LDB_ERR_OPERATIONS_ERROR;
373 /* Prepare context and handle */
374 ac = map_init_context(module, req);
376 return LDB_ERR_OPERATIONS_ERROR;
380 /* Prepare the local message */
381 ac->local_msg = ldb_msg_new(ac);
382 if (ac->local_msg == NULL) {
384 return LDB_ERR_OPERATIONS_ERROR;
386 ac->local_msg->dn = msg->dn;
388 /* Prepare the remote message */
389 remote_msg = ldb_msg_new(ac);
390 if (remote_msg == NULL) {
392 return LDB_ERR_OPERATIONS_ERROR;
394 remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
396 /* Split local from remote message */
397 ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
399 /* Prepare the remote operation */
400 ret = ldb_build_add_req(&ac->remote_req, module->ldb,
403 ac, map_op_remote_callback,
405 if (ret != LDB_SUCCESS) {
406 return LDB_ERR_OPERATIONS_ERROR;
409 if ((ac->local_msg->num_elements == 0) ||
410 ( ! map_check_local_db(ac->module))) {
411 /* No local data or db, just run the remote request */
412 return ldb_next_remote_request(ac->module, ac->remote_req);
415 /* Store remote DN in 'IS_MAPPED' */
416 /* TODO: use GUIDs here instead */
417 dn = ldb_dn_alloc_linearized(ac->local_msg, remote_msg->dn);
418 if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) {
419 return LDB_ERR_OPERATIONS_ERROR;
422 return map_add_do_local(ac);
425 /* Add the local record. */
426 static int map_add_do_local(struct map_context *ac)
428 struct ldb_request *local_req;
431 /* Prepare the local operation */
432 ret = ldb_build_add_req(&local_req, ac->module->ldb, ac,
436 map_op_local_callback,
438 if (ret != LDB_SUCCESS) {
439 return LDB_ERR_OPERATIONS_ERROR;
441 return ldb_next_request(ac->module, local_req);
444 /*****************************************************************************
446 *****************************************************************************/
448 /* Modify a record. */
449 int map_modify(struct ldb_module *module, struct ldb_request *req)
451 const struct ldb_message *msg = req->op.mod.message;
452 struct ldb_request *search_req;
453 struct ldb_message *remote_msg;
454 struct map_context *ac;
457 /* Do not manipulate our control entries */
458 if (ldb_dn_is_special(msg->dn)) {
459 return ldb_next_request(module, req);
462 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
463 if (!ldb_dn_check_local(module, msg->dn)) {
464 return ldb_next_request(module, req);
467 /* No mapping needed, skip to next module */
468 /* TODO: What if the remote part exists, the local doesn't,
469 * and this request wants to modify local data and thus
470 * add the local record? */
471 if (!ldb_msg_check_remote(module, msg)) {
472 return LDB_ERR_OPERATIONS_ERROR;
475 /* Prepare context and handle */
476 ac = map_init_context(module, req);
478 return LDB_ERR_OPERATIONS_ERROR;
481 /* Prepare the local message */
482 ac->local_msg = ldb_msg_new(ac);
483 if (ac->local_msg == NULL) {
485 return LDB_ERR_OPERATIONS_ERROR;
487 ac->local_msg->dn = msg->dn;
489 /* Prepare the remote message */
490 remote_msg = ldb_msg_new(ac->remote_req);
491 if (remote_msg == NULL) {
493 return LDB_ERR_OPERATIONS_ERROR;
495 remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
497 /* Split local from remote message */
498 ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
500 /* Prepare the remote operation */
501 ret = ldb_build_mod_req(&ac->remote_req, module->ldb,
504 ac, map_op_remote_callback,
506 if (ret != LDB_SUCCESS) {
507 return LDB_ERR_OPERATIONS_ERROR;
510 if ((ac->local_msg->num_elements == 0) ||
511 ( ! map_check_local_db(ac->module))) {
512 /* No local data or db, just run the remote request */
513 return ldb_next_remote_request(ac->module, ac->remote_req);
516 /* prepare the search operation */
517 ret = map_search_self_req(&search_req, ac, msg->dn);
518 if (ret != LDB_SUCCESS) {
519 return LDB_ERR_OPERATIONS_ERROR;
522 return ldb_next_request(module, search_req);
525 /* Modify the local record. */
526 static int map_modify_do_local(struct map_context *ac)
528 struct ldb_request *local_req;
532 if (ac->local_dn == NULL) {
533 /* No local record present, add it instead */
534 /* Add local 'IS_MAPPED' */
535 /* TODO: use GUIDs here instead */
536 if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED,
537 LDB_FLAG_MOD_ADD, NULL) != 0) {
538 return LDB_ERR_OPERATIONS_ERROR;
540 dn = ldb_dn_alloc_linearized(ac->local_msg,
541 ac->remote_req->op.mod.message->dn);
542 if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) {
543 return LDB_ERR_OPERATIONS_ERROR;
546 /* Prepare the local operation */
547 ret = ldb_build_add_req(&local_req, ac->module->ldb, ac,
551 map_op_local_callback,
553 if (ret != LDB_SUCCESS) {
554 return LDB_ERR_OPERATIONS_ERROR;
557 /* Prepare the local operation */
558 ret = ldb_build_mod_req(&local_req, ac->module->ldb, ac,
562 map_op_local_callback,
564 if (ret != LDB_SUCCESS) {
565 return LDB_ERR_OPERATIONS_ERROR;
569 return ldb_next_request(ac->module, local_req);
572 /*****************************************************************************
574 *****************************************************************************/
576 /* Delete a record. */
577 int map_delete(struct ldb_module *module, struct ldb_request *req)
579 struct ldb_request *search_req;
580 struct map_context *ac;
583 /* Do not manipulate our control entries */
584 if (ldb_dn_is_special(req->op.del.dn)) {
585 return ldb_next_request(module, req);
588 /* No mapping requested (perhaps no DN mapping specified).
589 * Skip to next module */
590 if (!ldb_dn_check_local(module, req->op.del.dn)) {
591 return ldb_next_request(module, req);
594 /* Prepare context and handle */
595 ac = map_init_context(module, req);
597 return LDB_ERR_OPERATIONS_ERROR;
600 /* Prepare the remote operation */
601 ret = ldb_build_del_req(&ac->remote_req, module->ldb, ac,
602 ldb_dn_map_local(module, ac, req->op.del.dn),
605 map_op_remote_callback,
607 if (ret != LDB_SUCCESS) {
608 return LDB_ERR_OPERATIONS_ERROR;
611 /* No local db, just run the remote request */
612 if (!map_check_local_db(ac->module)) {
613 /* Do the remote request. */
614 return ldb_next_remote_request(ac->module, ac->remote_req);
617 /* Prepare the search operation */
618 ret = map_search_self_req(&search_req, ac, req->op.del.dn);
619 if (ret != LDB_SUCCESS) {
621 return LDB_ERR_OPERATIONS_ERROR;
624 return ldb_next_request(module, search_req);
627 /* Delete the local record. */
628 static int map_delete_do_local(struct map_context *ac)
630 struct ldb_request *local_req;
633 /* No local record, continue remotely */
634 if (ac->local_dn == NULL) {
635 /* Do the remote request. */
636 return ldb_next_remote_request(ac->module, ac->remote_req);
639 /* Prepare the local operation */
640 ret = ldb_build_del_req(&local_req, ac->module->ldb, ac,
644 map_op_local_callback,
646 if (ret != LDB_SUCCESS) {
647 return LDB_ERR_OPERATIONS_ERROR;
649 return ldb_next_request(ac->module, local_req);
652 /*****************************************************************************
654 *****************************************************************************/
656 /* Rename a record. */
657 int map_rename(struct ldb_module *module, struct ldb_request *req)
659 struct ldb_request *search_req;
660 struct map_context *ac;
663 /* Do not manipulate our control entries */
664 if (ldb_dn_is_special(req->op.rename.olddn)) {
665 return ldb_next_request(module, req);
668 /* No mapping requested (perhaps no DN mapping specified).
669 * Skip to next module */
670 if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
671 (!ldb_dn_check_local(module, req->op.rename.newdn))) {
672 return ldb_next_request(module, req);
675 /* Rename into/out of the mapped partition requested, bail out */
676 if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
677 !ldb_dn_check_local(module, req->op.rename.newdn)) {
678 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
681 /* Prepare context and handle */
682 ac = map_init_context(module, req);
684 return LDB_ERR_OPERATIONS_ERROR;
687 /* Prepare the remote operation */
688 ret = ldb_build_rename_req(&ac->remote_req, module->ldb, ac,
689 ldb_dn_map_local(module, ac, req->op.rename.olddn),
690 ldb_dn_map_local(module, ac, req->op.rename.newdn),
692 ac, map_op_remote_callback,
694 if (ret != LDB_SUCCESS) {
695 return LDB_ERR_OPERATIONS_ERROR;
698 /* No local db, just run the remote request */
699 if (!map_check_local_db(ac->module)) {
700 /* Do the remote request. */
701 return ldb_next_remote_request(ac->module, ac->remote_req);
704 /* Prepare the search operation */
705 ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
706 if (ret != LDB_SUCCESS) {
708 return LDB_ERR_OPERATIONS_ERROR;
711 return ldb_next_request(module, search_req);
714 /* Rename the local record. */
715 static int map_rename_do_local(struct map_context *ac)
717 struct ldb_request *local_req;
720 /* No local record, continue remotely */
721 if (ac->local_dn == NULL) {
722 /* Do the remote request. */
723 return ldb_next_remote_request(ac->module, ac->remote_req);
726 /* Prepare the local operation */
727 ret = ldb_build_rename_req(&local_req, ac->module->ldb, ac,
728 ac->req->op.rename.olddn,
729 ac->req->op.rename.newdn,
732 map_rename_local_callback,
734 if (ret != LDB_SUCCESS) {
735 return LDB_ERR_OPERATIONS_ERROR;
738 return ldb_next_request(ac->module, local_req);
741 static int map_rename_local_callback(struct ldb_request *req,
742 struct ldb_reply *ares)
744 struct map_context *ac;
747 ac = talloc_get_type(req->context, struct map_context);
750 return ldb_module_done(ac->req, NULL, NULL,
751 LDB_ERR_OPERATIONS_ERROR);
753 if (ares->error != LDB_SUCCESS) {
754 return ldb_module_done(ac->req, ares->controls,
755 ares->response, ares->error);
758 if (ares->type != LDB_REPLY_DONE) {
759 ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
760 return ldb_module_done(ac->req, NULL, NULL,
761 LDB_ERR_OPERATIONS_ERROR);
764 /* proceed with next step */
765 ret = map_rename_do_fixup(ac);
766 if (ret != LDB_SUCCESS) {
767 return ldb_module_done(ac->req, NULL, NULL,
768 LDB_ERR_OPERATIONS_ERROR);
774 /* Update the local 'IS_MAPPED' attribute. */
775 static int map_rename_do_fixup(struct map_context *ac)
777 struct ldb_request *local_req;
779 /* Prepare the fixup operation */
780 /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
781 local_req = map_build_fixup_req(ac,
782 ac->req->op.rename.newdn,
783 ac->remote_req->op.rename.newdn,
785 map_op_local_callback);
786 if (local_req == NULL) {
787 return LDB_ERR_OPERATIONS_ERROR;
790 return ldb_next_request(ac->module, local_req);