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/>.
28 #include "ldb_map_private.h"
31 /* Mapping message elements
32 * ======================== */
34 /* Map a message element into the remote partition. */
35 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 struct ldb_message_element *el;
40 el = talloc_zero(mem_ctx, struct ldb_message_element);
46 el->num_values = old->num_values;
47 el->values = talloc_array(el, struct ldb_val, el->num_values);
48 if (el->values == NULL) {
54 el->name = map_attr_map_local(el, map, old->name);
56 for (i = 0; i < el->num_values; i++) {
57 el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
63 /* Add a message element either to a local or to a remote message,
64 * depending on whether it goes into the local or remote partition. */
65 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 const struct ldb_map_context *data = map_get_context(module);
68 const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
69 struct ldb_message_element *el=NULL;
70 struct ldb_context *ldb = ldb_module_get_ctx(module);
72 /* Unknown attribute: ignore */
74 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
75 "Not mapping attribute '%s': no mapping found\n",
85 if (map->u.convert.convert_local == NULL) {
86 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
87 "Not mapping attribute '%s': "
88 "'convert_local' not set\n",
95 el = ldb_msg_el_map_local(module, remote, map, old);
99 if (map->u.generate.generate_remote == NULL) {
100 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
101 "Not mapping attribute '%s': "
102 "'generate_remote' not set\n",
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?
113 map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
121 return ldb_msg_add(remote, el, old->flags);
124 el = talloc(local, struct ldb_message_element);
130 *el = *old; /* copy the old element */
132 return ldb_msg_add(local, el, old->flags);
136 * ================ */
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)
141 const struct ldb_map_context *data = map_get_context(module);
145 for (i = 0; i < msg->num_elements; i++) {
146 ret = map_attr_check_remote(data, msg->elements[i].name);
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)
159 /* const char * const names[]; */
160 struct ldb_context *ldb;
163 ldb = ldb_module_get_ctx(module);
165 for (i = 0; i < msg->num_elements; i++) {
166 /* Skip 'IS_MAPPED' */
167 if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
168 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
169 "Skipping attribute '%s'\n",
170 msg->elements[i].name);
174 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
184 static int map_add_do_local(struct map_context *ac);
185 static int map_modify_do_local(struct map_context *ac);
186 static int map_delete_do_local(struct map_context *ac);
187 static int map_rename_do_local(struct map_context *ac);
188 static int map_rename_do_fixup(struct map_context *ac);
189 static int map_rename_local_callback(struct ldb_request *req,
190 struct ldb_reply *ares);
193 /*****************************************************************************
194 * COMMON INBOUND functions
195 *****************************************************************************/
197 /* Store the DN of a single search result in context. */
198 static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
200 struct ldb_context *ldb;
201 struct map_context *ac;
204 ac = talloc_get_type(req->context, struct map_context);
205 ldb = ldb_module_get_ctx(ac->module);
208 return ldb_module_done(ac->req, NULL, NULL,
209 LDB_ERR_OPERATIONS_ERROR);
211 if (ares->error != LDB_SUCCESS) {
212 return ldb_module_done(ac->req, ares->controls,
213 ares->response, ares->error);
216 /* We are interested only in the single reply */
218 case LDB_REPLY_ENTRY:
219 /* We have already found a remote DN */
221 ldb_set_errstring(ldb,
222 "Too many results!");
223 return ldb_module_done(ac->req, NULL, NULL,
224 LDB_ERR_OPERATIONS_ERROR);
228 ac->local_dn = talloc_steal(ac, ares->message->dn);
233 switch (ac->req->operation) {
235 ret = map_modify_do_local(ac);
238 ret = map_delete_do_local(ac);
241 ret = map_rename_do_local(ac);
244 /* if we get here we have definitely a problem */
245 ret = LDB_ERR_OPERATIONS_ERROR;
247 if (ret != LDB_SUCCESS) {
248 return ldb_module_done(ac->req, NULL, NULL,
249 LDB_ERR_OPERATIONS_ERROR);
253 /* ignore referrals */
261 /* Build a request to search the local record by its DN. */
262 static int map_search_self_req(struct ldb_request **req,
263 struct map_context *ac,
266 /* attrs[] is returned from this function in
267 * ac->search_req->op.search.attrs, so it must be static, as
268 * otherwise the compiler can put it on the stack */
269 static const char * const attrs[] = { IS_MAPPED, NULL };
270 struct ldb_parse_tree *tree;
272 /* Limit search to records with 'IS_MAPPED' present */
273 tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
276 return LDB_ERR_OPERATIONS_ERROR;
279 *req = map_search_base_req(ac, dn, attrs, tree,
280 ac, map_search_self_callback);
282 return LDB_ERR_OPERATIONS_ERROR;
288 static int map_op_local_callback(struct ldb_request *req,
289 struct ldb_reply *ares)
291 struct ldb_context *ldb;
292 struct map_context *ac;
295 ac = talloc_get_type(req->context, struct map_context);
296 ldb = ldb_module_get_ctx(ac->module);
299 return ldb_module_done(ac->req, NULL, NULL,
300 LDB_ERR_OPERATIONS_ERROR);
302 if (ares->error != LDB_SUCCESS) {
303 return ldb_module_done(ac->req, ares->controls,
304 ares->response, ares->error);
307 if (ares->type != LDB_REPLY_DONE) {
308 ldb_set_errstring(ldb, "Invalid reply type!");
309 return ldb_module_done(ac->req, NULL, NULL,
310 LDB_ERR_OPERATIONS_ERROR);
313 /* Do the remote request. */
314 ret = ldb_next_remote_request(ac->module, ac->remote_req);
315 if (ret != LDB_SUCCESS) {
316 return ldb_module_done(ac->req, NULL, NULL,
317 LDB_ERR_OPERATIONS_ERROR);
323 static int map_op_remote_callback(struct ldb_request *req,
324 struct ldb_reply *ares)
326 struct ldb_context *ldb;
327 struct map_context *ac;
329 ac = talloc_get_type(req->context, struct map_context);
330 ldb = ldb_module_get_ctx(ac->module);
333 return ldb_module_done(ac->req, NULL, NULL,
334 LDB_ERR_OPERATIONS_ERROR);
336 if (ares->error != LDB_SUCCESS) {
337 return ldb_module_done(ac->req, ares->controls,
338 ares->response, ares->error);
341 if (ares->type != LDB_REPLY_DONE) {
342 ldb_set_errstring(ldb, "Invalid reply type!");
343 return ldb_module_done(ac->req, NULL, NULL,
344 LDB_ERR_OPERATIONS_ERROR);
347 return ldb_module_done(ac->req, ares->controls,
348 ares->response, ares->error);
352 /*****************************************************************************
354 *****************************************************************************/
358 int map_add(struct ldb_module *module, struct ldb_request *req)
360 const struct ldb_message *msg = req->op.add.message;
361 struct ldb_context *ldb;
362 struct map_context *ac;
363 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 dn = ldb_dn_alloc_linearized(ac->local_msg, remote_msg->dn);
429 if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) {
430 return LDB_ERR_OPERATIONS_ERROR;
433 return map_add_do_local(ac);
436 /* Add the local record. */
437 static int map_add_do_local(struct map_context *ac)
439 struct ldb_request *local_req;
440 struct ldb_context *ldb;
443 ldb = ldb_module_get_ctx(ac->module);
445 /* Prepare the local operation */
446 ret = ldb_build_add_req(&local_req, ldb, ac,
450 map_op_local_callback,
452 if (ret != LDB_SUCCESS) {
453 return LDB_ERR_OPERATIONS_ERROR;
455 return ldb_next_request(ac->module, local_req);
458 /*****************************************************************************
460 *****************************************************************************/
462 /* Modify a record. */
463 int map_modify(struct ldb_module *module, struct ldb_request *req)
465 const struct ldb_message *msg = req->op.mod.message;
466 struct ldb_request *search_req;
467 struct ldb_message *remote_msg;
468 struct ldb_context *ldb;
469 struct map_context *ac;
472 ldb = ldb_module_get_ctx(module);
474 /* Do not manipulate our control entries */
475 if (ldb_dn_is_special(msg->dn)) {
476 return ldb_next_request(module, req);
479 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
480 if (!ldb_dn_check_local(module, msg->dn)) {
481 return ldb_next_request(module, req);
484 /* No mapping needed, skip to next module */
485 /* TODO: What if the remote part exists, the local doesn't,
486 * and this request wants to modify local data and thus
487 * add the local record? */
488 if (!ldb_msg_check_remote(module, msg)) {
489 return LDB_ERR_OPERATIONS_ERROR;
492 /* Prepare context and handle */
493 ac = map_init_context(module, req);
495 return LDB_ERR_OPERATIONS_ERROR;
498 /* Prepare the local message */
499 ac->local_msg = ldb_msg_new(ac);
500 if (ac->local_msg == NULL) {
502 return LDB_ERR_OPERATIONS_ERROR;
504 ac->local_msg->dn = msg->dn;
506 /* Prepare the remote message */
507 remote_msg = ldb_msg_new(ac->remote_req);
508 if (remote_msg == NULL) {
510 return LDB_ERR_OPERATIONS_ERROR;
512 remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
514 /* Split local from remote message */
515 ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
517 /* Prepare the remote operation */
518 ret = ldb_build_mod_req(&ac->remote_req, ldb,
521 ac, map_op_remote_callback,
523 if (ret != LDB_SUCCESS) {
524 return LDB_ERR_OPERATIONS_ERROR;
527 if ((ac->local_msg->num_elements == 0) ||
528 ( ! map_check_local_db(ac->module))) {
529 /* No local data or db, just run the remote request */
530 return ldb_next_remote_request(ac->module, ac->remote_req);
533 /* prepare the search operation */
534 ret = map_search_self_req(&search_req, ac, msg->dn);
535 if (ret != LDB_SUCCESS) {
536 return LDB_ERR_OPERATIONS_ERROR;
539 return ldb_next_request(module, search_req);
542 /* Modify the local record. */
543 static int map_modify_do_local(struct map_context *ac)
545 struct ldb_request *local_req;
546 struct ldb_context *ldb;
550 ldb = ldb_module_get_ctx(ac->module);
552 if (ac->local_dn == NULL) {
553 /* No local record present, add it instead */
554 /* Add local 'IS_MAPPED' */
555 /* TODO: use GUIDs here instead */
556 if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED,
557 LDB_FLAG_MOD_ADD, NULL) != 0) {
558 return LDB_ERR_OPERATIONS_ERROR;
560 dn = ldb_dn_alloc_linearized(ac->local_msg,
561 ac->remote_req->op.mod.message->dn);
562 if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) {
563 return LDB_ERR_OPERATIONS_ERROR;
566 /* Prepare the local operation */
567 ret = ldb_build_add_req(&local_req, ldb, ac,
571 map_op_local_callback,
573 if (ret != LDB_SUCCESS) {
574 return LDB_ERR_OPERATIONS_ERROR;
577 /* Prepare the local operation */
578 ret = ldb_build_mod_req(&local_req, ldb, ac,
582 map_op_local_callback,
584 if (ret != LDB_SUCCESS) {
585 return LDB_ERR_OPERATIONS_ERROR;
589 return ldb_next_request(ac->module, local_req);
592 /*****************************************************************************
594 *****************************************************************************/
596 /* Delete a record. */
597 int map_delete(struct ldb_module *module, struct ldb_request *req)
599 struct ldb_request *search_req;
600 struct ldb_context *ldb;
601 struct map_context *ac;
604 ldb = ldb_module_get_ctx(module);
606 /* Do not manipulate our control entries */
607 if (ldb_dn_is_special(req->op.del.dn)) {
608 return ldb_next_request(module, req);
611 /* No mapping requested (perhaps no DN mapping specified).
612 * Skip to next module */
613 if (!ldb_dn_check_local(module, req->op.del.dn)) {
614 return ldb_next_request(module, req);
617 /* Prepare context and handle */
618 ac = map_init_context(module, req);
620 return LDB_ERR_OPERATIONS_ERROR;
623 /* Prepare the remote operation */
624 ret = ldb_build_del_req(&ac->remote_req, ldb, ac,
625 ldb_dn_map_local(module, ac, req->op.del.dn),
628 map_op_remote_callback,
630 if (ret != LDB_SUCCESS) {
631 return LDB_ERR_OPERATIONS_ERROR;
634 /* No local db, just run the remote request */
635 if (!map_check_local_db(ac->module)) {
636 /* Do the remote request. */
637 return ldb_next_remote_request(ac->module, ac->remote_req);
640 /* Prepare the search operation */
641 ret = map_search_self_req(&search_req, ac, req->op.del.dn);
642 if (ret != LDB_SUCCESS) {
644 return LDB_ERR_OPERATIONS_ERROR;
647 return ldb_next_request(module, search_req);
650 /* Delete the local record. */
651 static int map_delete_do_local(struct map_context *ac)
653 struct ldb_request *local_req;
654 struct ldb_context *ldb;
657 ldb = ldb_module_get_ctx(ac->module);
659 /* No local record, continue remotely */
660 if (ac->local_dn == NULL) {
661 /* Do the remote request. */
662 return ldb_next_remote_request(ac->module, ac->remote_req);
665 /* Prepare the local operation */
666 ret = ldb_build_del_req(&local_req, ldb, ac,
670 map_op_local_callback,
672 if (ret != LDB_SUCCESS) {
673 return LDB_ERR_OPERATIONS_ERROR;
675 return ldb_next_request(ac->module, local_req);
678 /*****************************************************************************
680 *****************************************************************************/
682 /* Rename a record. */
683 int map_rename(struct ldb_module *module, struct ldb_request *req)
685 struct ldb_request *search_req;
686 struct ldb_context *ldb;
687 struct map_context *ac;
690 ldb = ldb_module_get_ctx(module);
692 /* Do not manipulate our control entries */
693 if (ldb_dn_is_special(req->op.rename.olddn)) {
694 return ldb_next_request(module, req);
697 /* No mapping requested (perhaps no DN mapping specified).
698 * Skip to next module */
699 if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
700 (!ldb_dn_check_local(module, req->op.rename.newdn))) {
701 return ldb_next_request(module, req);
704 /* Rename into/out of the mapped partition requested, bail out */
705 if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
706 !ldb_dn_check_local(module, req->op.rename.newdn)) {
707 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
710 /* Prepare context and handle */
711 ac = map_init_context(module, req);
713 return LDB_ERR_OPERATIONS_ERROR;
716 /* Prepare the remote operation */
717 ret = ldb_build_rename_req(&ac->remote_req, ldb, ac,
718 ldb_dn_map_local(module, ac, req->op.rename.olddn),
719 ldb_dn_map_local(module, ac, req->op.rename.newdn),
721 ac, map_op_remote_callback,
723 if (ret != LDB_SUCCESS) {
724 return LDB_ERR_OPERATIONS_ERROR;
727 /* No local db, just run the remote request */
728 if (!map_check_local_db(ac->module)) {
729 /* Do the remote request. */
730 return ldb_next_remote_request(ac->module, ac->remote_req);
733 /* Prepare the search operation */
734 ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
735 if (ret != LDB_SUCCESS) {
737 return LDB_ERR_OPERATIONS_ERROR;
740 return ldb_next_request(module, search_req);
743 /* Rename the local record. */
744 static int map_rename_do_local(struct map_context *ac)
746 struct ldb_request *local_req;
747 struct ldb_context *ldb;
750 ldb = ldb_module_get_ctx(ac->module);
752 /* No local record, continue remotely */
753 if (ac->local_dn == NULL) {
754 /* Do the remote request. */
755 return ldb_next_remote_request(ac->module, ac->remote_req);
758 /* Prepare the local operation */
759 ret = ldb_build_rename_req(&local_req, ldb, ac,
760 ac->req->op.rename.olddn,
761 ac->req->op.rename.newdn,
764 map_rename_local_callback,
766 if (ret != LDB_SUCCESS) {
767 return LDB_ERR_OPERATIONS_ERROR;
770 return ldb_next_request(ac->module, local_req);
773 static int map_rename_local_callback(struct ldb_request *req,
774 struct ldb_reply *ares)
776 struct ldb_context *ldb;
777 struct map_context *ac;
780 ac = talloc_get_type(req->context, struct map_context);
781 ldb = ldb_module_get_ctx(ac->module);
784 return ldb_module_done(ac->req, NULL, NULL,
785 LDB_ERR_OPERATIONS_ERROR);
787 if (ares->error != LDB_SUCCESS) {
788 return ldb_module_done(ac->req, ares->controls,
789 ares->response, ares->error);
792 if (ares->type != LDB_REPLY_DONE) {
793 ldb_set_errstring(ldb, "Invalid reply type!");
794 return ldb_module_done(ac->req, NULL, NULL,
795 LDB_ERR_OPERATIONS_ERROR);
798 /* proceed with next step */
799 ret = map_rename_do_fixup(ac);
800 if (ret != LDB_SUCCESS) {
801 return ldb_module_done(ac->req, NULL, NULL,
802 LDB_ERR_OPERATIONS_ERROR);
808 /* Update the local 'IS_MAPPED' attribute. */
809 static int map_rename_do_fixup(struct map_context *ac)
811 struct ldb_request *local_req;
813 /* Prepare the fixup operation */
814 /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
815 local_req = map_build_fixup_req(ac,
816 ac->req->op.rename.newdn,
817 ac->remote_req->op.rename.newdn,
819 map_op_local_callback);
820 if (local_req == NULL) {
821 return LDB_ERR_OPERATIONS_ERROR;
824 return ldb_next_request(ac->module, local_req);