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"
29 #include "ldb_map_private.h"
32 /* Mapping message elements
33 * ======================== */
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)
38 struct ldb_message_element *el;
41 el = talloc_zero(mem_ctx, struct ldb_message_element);
47 el->num_values = old->num_values;
48 el->values = talloc_array(el, struct ldb_val, el->num_values);
49 if (el->values == NULL) {
55 el->name = map_attr_map_local(el, map, old->name);
57 for (i = 0; i < el->num_values; i++) {
58 el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
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)
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);
73 /* Unknown attribute: ignore */
75 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
76 "Not mapping attribute '%s': no mapping found",
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",
96 el = ldb_msg_el_map_local(module, remote, map, old);
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",
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[]; */
161 struct ldb_context *ldb;
164 ldb = ldb_module_get_ctx(module);
166 for (i = 0; i < msg->num_elements; i++) {
167 /* Skip 'IS_MAPPED' */
168 if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
169 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
170 "Skipping attribute '%s'",
171 msg->elements[i].name);
175 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
185 static int map_add_do_local(struct map_context *ac);
186 static int map_modify_do_local(struct map_context *ac);
187 static int map_delete_do_local(struct map_context *ac);
188 static int map_rename_do_local(struct map_context *ac);
189 static int map_rename_do_fixup(struct map_context *ac);
190 static int map_rename_local_callback(struct ldb_request *req,
191 struct ldb_reply *ares);
194 /*****************************************************************************
195 * COMMON INBOUND functions
196 *****************************************************************************/
198 /* Store the DN of a single search result in context. */
199 static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
201 struct ldb_context *ldb;
202 struct map_context *ac;
205 ac = talloc_get_type(req->context, struct map_context);
206 ldb = ldb_module_get_ctx(ac->module);
209 return ldb_module_done(ac->req, NULL, NULL,
210 LDB_ERR_OPERATIONS_ERROR);
212 if (ares->error != LDB_SUCCESS) {
213 return ldb_module_done(ac->req, ares->controls,
214 ares->response, ares->error);
217 /* We are interested only in the single reply */
219 case LDB_REPLY_ENTRY:
220 /* We have already found a remote DN */
222 ldb_set_errstring(ldb,
223 "Too many results!");
224 return ldb_module_done(ac->req, NULL, NULL,
225 LDB_ERR_OPERATIONS_ERROR);
229 ac->local_dn = talloc_steal(ac, ares->message->dn);
234 switch (ac->req->operation) {
236 ret = map_modify_do_local(ac);
239 ret = map_delete_do_local(ac);
242 ret = map_rename_do_local(ac);
245 /* if we get here we have definitely a problem */
246 ret = LDB_ERR_OPERATIONS_ERROR;
248 if (ret != LDB_SUCCESS) {
249 return ldb_module_done(ac->req, NULL, NULL,
250 LDB_ERR_OPERATIONS_ERROR);
254 /* ignore referrals */
262 /* Build a request to search the local record by its DN. */
263 static int map_search_self_req(struct ldb_request **req,
264 struct map_context *ac,
267 /* attrs[] is returned from this function in
268 * ac->search_req->op.search.attrs, so it must be static, as
269 * otherwise the compiler can put it on the stack */
270 static const char * const attrs[] = { IS_MAPPED, NULL };
271 struct ldb_parse_tree *tree;
273 /* Limit search to records with 'IS_MAPPED' present */
274 tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
277 return LDB_ERR_OPERATIONS_ERROR;
280 *req = map_search_base_req(ac, dn, attrs, tree,
281 ac, map_search_self_callback);
283 return LDB_ERR_OPERATIONS_ERROR;
289 static int map_op_local_callback(struct ldb_request *req,
290 struct ldb_reply *ares)
292 struct ldb_context *ldb;
293 struct map_context *ac;
296 ac = talloc_get_type(req->context, struct map_context);
297 ldb = ldb_module_get_ctx(ac->module);
300 return ldb_module_done(ac->req, NULL, NULL,
301 LDB_ERR_OPERATIONS_ERROR);
303 if (ares->error != LDB_SUCCESS) {
304 return ldb_module_done(ac->req, ares->controls,
305 ares->response, ares->error);
308 if (ares->type != LDB_REPLY_DONE) {
309 ldb_set_errstring(ldb, "Invalid reply type!");
310 return ldb_module_done(ac->req, NULL, NULL,
311 LDB_ERR_OPERATIONS_ERROR);
314 /* Do the remote request. */
315 ret = ldb_next_remote_request(ac->module, ac->remote_req);
316 if (ret != LDB_SUCCESS) {
317 return ldb_module_done(ac->req, NULL, NULL,
318 LDB_ERR_OPERATIONS_ERROR);
324 static int map_op_remote_callback(struct ldb_request *req,
325 struct ldb_reply *ares)
327 struct ldb_context *ldb;
328 struct map_context *ac;
330 ac = talloc_get_type(req->context, struct map_context);
331 ldb = ldb_module_get_ctx(ac->module);
334 return ldb_module_done(ac->req, NULL, NULL,
335 LDB_ERR_OPERATIONS_ERROR);
337 if (ares->error != LDB_SUCCESS) {
338 return ldb_module_done(ac->req, ares->controls,
339 ares->response, ares->error);
342 if (ares->type != LDB_REPLY_DONE) {
343 ldb_set_errstring(ldb, "Invalid reply type!");
344 return ldb_module_done(ac->req, NULL, NULL,
345 LDB_ERR_OPERATIONS_ERROR);
348 return ldb_module_done(ac->req, ares->controls,
349 ares->response, ares->error);
353 /*****************************************************************************
355 *****************************************************************************/
359 int map_add(struct ldb_module *module, struct ldb_request *req)
361 const struct ldb_message *msg = req->op.add.message;
362 struct ldb_context *ldb;
363 struct map_context *ac;
364 struct ldb_message *remote_msg;
367 ldb = ldb_module_get_ctx(module);
369 /* Do not manipulate our control entries */
370 if (ldb_dn_is_special(msg->dn)) {
371 return ldb_next_request(module, req);
374 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
375 if (!ldb_dn_check_local(module, msg->dn)) {
376 return ldb_next_request(module, req);
379 /* No mapping needed, fail */
380 if (!ldb_msg_check_remote(module, msg)) {
381 return LDB_ERR_OPERATIONS_ERROR;
384 /* Prepare context and handle */
385 ac = map_init_context(module, req);
387 return LDB_ERR_OPERATIONS_ERROR;
391 /* Prepare the local message */
392 ac->local_msg = ldb_msg_new(ac);
393 if (ac->local_msg == NULL) {
395 return LDB_ERR_OPERATIONS_ERROR;
397 ac->local_msg->dn = msg->dn;
399 /* Prepare the remote message */
400 remote_msg = ldb_msg_new(ac);
401 if (remote_msg == NULL) {
403 return LDB_ERR_OPERATIONS_ERROR;
405 remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
407 /* Split local from remote message */
408 ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
410 /* Prepare the remote operation */
411 ret = ldb_build_add_req(&ac->remote_req, ldb,
414 ac, map_op_remote_callback,
416 if (ret != LDB_SUCCESS) {
417 return LDB_ERR_OPERATIONS_ERROR;
420 if ((ac->local_msg->num_elements == 0) ||
421 ( ! map_check_local_db(ac->module))) {
422 /* No local data or db, just run the remote request */
423 return ldb_next_remote_request(ac->module, ac->remote_req);
426 /* Store remote DN in 'IS_MAPPED' */
427 /* TODO: use GUIDs here instead */
428 if (ldb_msg_add_dn(ac->local_msg, IS_MAPPED, remote_msg->dn) != 0) {
429 return LDB_ERR_OPERATIONS_ERROR;
432 return map_add_do_local(ac);
435 /* Add the local record. */
436 static int map_add_do_local(struct map_context *ac)
438 struct ldb_request *local_req;
439 struct ldb_context *ldb;
442 ldb = ldb_module_get_ctx(ac->module);
444 /* Prepare the local operation */
445 ret = ldb_build_add_req(&local_req, ldb, ac,
449 map_op_local_callback,
451 if (ret != LDB_SUCCESS) {
452 return LDB_ERR_OPERATIONS_ERROR;
454 return ldb_next_request(ac->module, local_req);
457 /*****************************************************************************
459 *****************************************************************************/
461 /* Modify a record. */
462 int map_modify(struct ldb_module *module, struct ldb_request *req)
464 const struct ldb_message *msg = req->op.mod.message;
465 struct ldb_request *search_req;
466 struct ldb_message *remote_msg;
467 struct ldb_context *ldb;
468 struct map_context *ac;
471 ldb = ldb_module_get_ctx(module);
473 /* Do not manipulate our control entries */
474 if (ldb_dn_is_special(msg->dn)) {
475 return ldb_next_request(module, req);
478 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
479 if (!ldb_dn_check_local(module, msg->dn)) {
480 return ldb_next_request(module, req);
483 /* No mapping needed, skip to next module */
484 /* TODO: What if the remote part exists, the local doesn't,
485 * and this request wants to modify local data and thus
486 * add the local record? */
487 if (!ldb_msg_check_remote(module, msg)) {
488 return LDB_ERR_OPERATIONS_ERROR;
491 /* Prepare context and handle */
492 ac = map_init_context(module, req);
494 return LDB_ERR_OPERATIONS_ERROR;
497 /* Prepare the local message */
498 ac->local_msg = ldb_msg_new(ac);
499 if (ac->local_msg == NULL) {
501 return LDB_ERR_OPERATIONS_ERROR;
503 ac->local_msg->dn = msg->dn;
505 /* Prepare the remote message */
506 remote_msg = ldb_msg_new(ac->remote_req);
507 if (remote_msg == NULL) {
509 return LDB_ERR_OPERATIONS_ERROR;
511 remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
513 /* Split local from remote message */
514 ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
516 /* Prepare the remote operation */
517 ret = ldb_build_mod_req(&ac->remote_req, ldb,
520 ac, map_op_remote_callback,
522 if (ret != LDB_SUCCESS) {
523 return LDB_ERR_OPERATIONS_ERROR;
526 if ((ac->local_msg->num_elements == 0) ||
527 ( ! map_check_local_db(ac->module))) {
528 /* No local data or db, just run the remote request */
529 return ldb_next_remote_request(ac->module, ac->remote_req);
532 /* prepare the search operation */
533 ret = map_search_self_req(&search_req, ac, msg->dn);
534 if (ret != LDB_SUCCESS) {
535 return LDB_ERR_OPERATIONS_ERROR;
538 return ldb_next_request(module, search_req);
541 /* Modify the local record. */
542 static int map_modify_do_local(struct map_context *ac)
544 struct ldb_request *local_req;
545 struct ldb_context *ldb;
548 ldb = ldb_module_get_ctx(ac->module);
550 if (ac->local_dn == NULL) {
551 /* No local record present, add it instead */
552 /* Add local 'IS_MAPPED' */
553 /* TODO: use GUIDs here instead */
554 if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED,
555 LDB_FLAG_MOD_ADD, NULL) != 0) {
556 return LDB_ERR_OPERATIONS_ERROR;
558 if (ldb_msg_add_dn(ac->local_msg, IS_MAPPED,
559 ac->remote_req->op.mod.message->dn) != 0) {
560 return LDB_ERR_OPERATIONS_ERROR;
563 /* Prepare the local operation */
564 ret = ldb_build_add_req(&local_req, ldb, ac,
568 map_op_local_callback,
570 if (ret != LDB_SUCCESS) {
571 return LDB_ERR_OPERATIONS_ERROR;
574 /* Prepare the local operation */
575 ret = ldb_build_mod_req(&local_req, ldb, ac,
579 map_op_local_callback,
581 if (ret != LDB_SUCCESS) {
582 return LDB_ERR_OPERATIONS_ERROR;
586 return ldb_next_request(ac->module, local_req);
589 /*****************************************************************************
591 *****************************************************************************/
593 /* Delete a record. */
594 int map_delete(struct ldb_module *module, struct ldb_request *req)
596 struct ldb_request *search_req;
597 struct ldb_context *ldb;
598 struct map_context *ac;
601 ldb = ldb_module_get_ctx(module);
603 /* Do not manipulate our control entries */
604 if (ldb_dn_is_special(req->op.del.dn)) {
605 return ldb_next_request(module, req);
608 /* No mapping requested (perhaps no DN mapping specified).
609 * Skip to next module */
610 if (!ldb_dn_check_local(module, req->op.del.dn)) {
611 return ldb_next_request(module, req);
614 /* Prepare context and handle */
615 ac = map_init_context(module, req);
617 return LDB_ERR_OPERATIONS_ERROR;
620 /* Prepare the remote operation */
621 ret = ldb_build_del_req(&ac->remote_req, ldb, ac,
622 ldb_dn_map_local(module, ac, req->op.del.dn),
625 map_op_remote_callback,
627 if (ret != LDB_SUCCESS) {
628 return LDB_ERR_OPERATIONS_ERROR;
631 /* No local db, just run the remote request */
632 if (!map_check_local_db(ac->module)) {
633 /* Do the remote request. */
634 return ldb_next_remote_request(ac->module, ac->remote_req);
637 /* Prepare the search operation */
638 ret = map_search_self_req(&search_req, ac, req->op.del.dn);
639 if (ret != LDB_SUCCESS) {
641 return LDB_ERR_OPERATIONS_ERROR;
644 return ldb_next_request(module, search_req);
647 /* Delete the local record. */
648 static int map_delete_do_local(struct map_context *ac)
650 struct ldb_request *local_req;
651 struct ldb_context *ldb;
654 ldb = ldb_module_get_ctx(ac->module);
656 /* No local record, continue remotely */
657 if (ac->local_dn == NULL) {
658 /* Do the remote request. */
659 return ldb_next_remote_request(ac->module, ac->remote_req);
662 /* Prepare the local operation */
663 ret = ldb_build_del_req(&local_req, ldb, ac,
667 map_op_local_callback,
669 if (ret != LDB_SUCCESS) {
670 return LDB_ERR_OPERATIONS_ERROR;
672 return ldb_next_request(ac->module, local_req);
675 /*****************************************************************************
677 *****************************************************************************/
679 /* Rename a record. */
680 int map_rename(struct ldb_module *module, struct ldb_request *req)
682 struct ldb_request *search_req;
683 struct ldb_context *ldb;
684 struct map_context *ac;
687 ldb = ldb_module_get_ctx(module);
689 /* Do not manipulate our control entries */
690 if (ldb_dn_is_special(req->op.rename.olddn)) {
691 return ldb_next_request(module, req);
694 /* No mapping requested (perhaps no DN mapping specified).
695 * Skip to next module */
696 if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
697 (!ldb_dn_check_local(module, req->op.rename.newdn))) {
698 return ldb_next_request(module, req);
701 /* Rename into/out of the mapped partition requested, bail out */
702 if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
703 !ldb_dn_check_local(module, req->op.rename.newdn)) {
704 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
707 /* Prepare context and handle */
708 ac = map_init_context(module, req);
710 return LDB_ERR_OPERATIONS_ERROR;
713 /* Prepare the remote operation */
714 ret = ldb_build_rename_req(&ac->remote_req, ldb, ac,
715 ldb_dn_map_local(module, ac, req->op.rename.olddn),
716 ldb_dn_map_local(module, ac, req->op.rename.newdn),
718 ac, map_op_remote_callback,
720 if (ret != LDB_SUCCESS) {
721 return LDB_ERR_OPERATIONS_ERROR;
724 /* No local db, just run the remote request */
725 if (!map_check_local_db(ac->module)) {
726 /* Do the remote request. */
727 return ldb_next_remote_request(ac->module, ac->remote_req);
730 /* Prepare the search operation */
731 ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
732 if (ret != LDB_SUCCESS) {
734 return LDB_ERR_OPERATIONS_ERROR;
737 return ldb_next_request(module, search_req);
740 /* Rename the local record. */
741 static int map_rename_do_local(struct map_context *ac)
743 struct ldb_request *local_req;
744 struct ldb_context *ldb;
747 ldb = ldb_module_get_ctx(ac->module);
749 /* No local record, continue remotely */
750 if (ac->local_dn == NULL) {
751 /* Do the remote request. */
752 return ldb_next_remote_request(ac->module, ac->remote_req);
755 /* Prepare the local operation */
756 ret = ldb_build_rename_req(&local_req, ldb, ac,
757 ac->req->op.rename.olddn,
758 ac->req->op.rename.newdn,
761 map_rename_local_callback,
763 if (ret != LDB_SUCCESS) {
764 return LDB_ERR_OPERATIONS_ERROR;
767 return ldb_next_request(ac->module, local_req);
770 static int map_rename_local_callback(struct ldb_request *req,
771 struct ldb_reply *ares)
773 struct ldb_context *ldb;
774 struct map_context *ac;
777 ac = talloc_get_type(req->context, struct map_context);
778 ldb = ldb_module_get_ctx(ac->module);
781 return ldb_module_done(ac->req, NULL, NULL,
782 LDB_ERR_OPERATIONS_ERROR);
784 if (ares->error != LDB_SUCCESS) {
785 return ldb_module_done(ac->req, ares->controls,
786 ares->response, ares->error);
789 if (ares->type != LDB_REPLY_DONE) {
790 ldb_set_errstring(ldb, "Invalid reply type!");
791 return ldb_module_done(ac->req, NULL, NULL,
792 LDB_ERR_OPERATIONS_ERROR);
795 /* proceed with next step */
796 ret = map_rename_do_fixup(ac);
797 if (ret != LDB_SUCCESS) {
798 return ldb_module_done(ac->req, NULL, NULL,
799 LDB_ERR_OPERATIONS_ERROR);
805 /* Update the local 'IS_MAPPED' attribute. */
806 static int map_rename_do_fixup(struct map_context *ac)
808 struct ldb_request *local_req;
810 /* Prepare the fixup operation */
811 /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
812 local_req = map_build_fixup_req(ac,
813 ac->req->op.rename.newdn,
814 ac->remote_req->op.rename.newdn,
816 map_op_local_callback);
817 if (local_req == NULL) {
818 return LDB_ERR_OPERATIONS_ERROR;
821 return ldb_next_request(ac->module, local_req);