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
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.
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, see <http://www.gnu.org/licenses/>.
26 #include "ldb/include/includes.h"
28 #include "ldb/modules/ldb_map.h"
29 #include "ldb/modules/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
;
72 /* Unknown attribute: ignore */
74 ldb_debug(module
->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(module
->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(module
->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[]; */
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
);
171 ret
= ldb_msg_el_partition(module
, local
, remote
, msg
, msg
->elements
[i
].name
, &msg
->elements
[i
]);
181 /* Inbound requests: add, modify, rename, delete
182 * ============================================= */
184 /* Add the remote record. */
185 int map_add_do_remote(struct ldb_handle
*handle
)
187 struct map_context
*ac
;
189 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
191 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->remote_req
);
193 ac
->step
= MAP_ADD_REMOTE
;
195 handle
->state
= LDB_ASYNC_INIT
;
196 handle
->status
= LDB_SUCCESS
;
198 return ldb_next_remote_request(ac
->module
, ac
->remote_req
);
201 /* Add the local record. */
202 int map_add_do_local(struct ldb_handle
*handle
)
204 struct map_context
*ac
;
206 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
208 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->local_req
);
210 ac
->step
= MAP_ADD_LOCAL
;
212 handle
->state
= LDB_ASYNC_INIT
;
213 handle
->status
= LDB_SUCCESS
;
215 return ldb_next_request(ac
->module
, ac
->local_req
);
219 int map_add(struct ldb_module
*module
, struct ldb_request
*req
)
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
;
227 /* Do not manipulate our control entries */
228 if (ldb_dn_is_special(msg
->dn
)) {
229 return ldb_next_request(module
, req
);
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
);
237 /* No mapping needed, fail */
238 if (!ldb_msg_check_remote(module
, msg
)) {
239 return LDB_ERR_OPERATIONS_ERROR
;
242 /* Prepare context and handle */
243 h
= map_init_handle(req
, module
);
245 return LDB_ERR_OPERATIONS_ERROR
;
247 ac
= talloc_get_type(h
->private_data
, struct map_context
);
249 /* Prepare the local operation */
250 ac
->local_req
= talloc(ac
, struct ldb_request
);
251 if (ac
->local_req
== NULL
) {
255 *(ac
->local_req
) = *req
; /* copy the request */
257 ac
->local_req
->context
= NULL
;
258 ac
->local_req
->callback
= NULL
;
260 /* Prepare the remote operation */
261 ac
->remote_req
= talloc(ac
, struct ldb_request
);
262 if (ac
->remote_req
== NULL
) {
266 *(ac
->remote_req
) = *req
; /* copy the request */
268 ac
->remote_req
->context
= NULL
;
269 ac
->remote_req
->callback
= NULL
;
271 /* Prepare the local message */
272 local
= ldb_msg_new(ac
->local_req
);
278 /* Prepare the remote message */
279 remote
= ldb_msg_new(ac
->remote_req
);
280 if (remote
== NULL
) {
283 remote
->dn
= ldb_dn_map_local(ac
->module
, remote
, msg
->dn
);
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
;
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
);
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) {
304 req
->handle
= h
; /* return our own handle to deal with this call */
305 return map_add_do_local(h
);
311 return LDB_ERR_OPERATIONS_ERROR
;
314 /* Modify the remote record. */
315 int map_modify_do_remote(struct ldb_handle
*handle
)
317 struct map_context
*ac
;
319 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
321 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->remote_req
);
323 ac
->step
= MAP_MODIFY_REMOTE
;
325 handle
->state
= LDB_ASYNC_INIT
;
326 handle
->status
= LDB_SUCCESS
;
328 return ldb_next_remote_request(ac
->module
, ac
->remote_req
);
331 /* Modify the local record. */
332 int map_modify_do_local(struct ldb_handle
*handle
)
334 struct map_context
*ac
;
335 struct ldb_message
*msg
;
338 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
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
);
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
;
350 if (ldb_msg_add_string(msg
, IS_MAPPED
, dn
) != 0) {
351 return LDB_ERR_OPERATIONS_ERROR
;
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. */
361 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->local_req
);
363 ac
->step
= MAP_MODIFY_LOCAL
;
365 handle
->state
= LDB_ASYNC_INIT
;
366 handle
->status
= LDB_SUCCESS
;
368 return ldb_next_request(ac
->module
, ac
->local_req
);
371 /* Modify a record. */
372 int map_modify(struct ldb_module
*module
, struct ldb_request
*req
)
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
;
379 /* Do not manipulate our control entries */
380 if (ldb_dn_is_special(msg
->dn
)) {
381 return ldb_next_request(module
, req
);
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
);
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
;
397 /* Prepare context and handle */
398 h
= map_init_handle(req
, module
);
400 return LDB_ERR_OPERATIONS_ERROR
;
402 ac
= talloc_get_type(h
->private_data
, struct map_context
);
404 /* Prepare the local operation */
405 ac
->local_req
= talloc(ac
, struct ldb_request
);
406 if (ac
->local_req
== NULL
) {
410 *(ac
->local_req
) = *req
; /* copy the request */
412 ac
->local_req
->context
= NULL
;
413 ac
->local_req
->callback
= NULL
;
415 /* Prepare the remote operation */
416 ac
->remote_req
= talloc(ac
, struct ldb_request
);
417 if (ac
->remote_req
== NULL
) {
421 *(ac
->remote_req
) = *req
; /* copy the request */
423 ac
->remote_req
->context
= NULL
;
424 ac
->remote_req
->callback
= NULL
;
426 /* Prepare the local message */
427 local
= ldb_msg_new(ac
->local_req
);
433 /* Prepare the remote message */
434 remote
= ldb_msg_new(ac
->remote_req
);
435 if (remote
== NULL
) {
438 remote
->dn
= ldb_dn_map_local(ac
->module
, remote
, msg
->dn
);
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
;
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
);
452 /* prepare the search operation */
453 ac
->search_req
= map_search_self_req(ac
, msg
->dn
);
454 if (ac
->search_req
== NULL
) {
458 ac
->step
= MAP_SEARCH_SELF_MODIFY
;
460 req
->handle
= h
; /* return our own handle to deal with this call */
461 return ldb_next_request(module
, ac
->search_req
);
467 return LDB_ERR_OPERATIONS_ERROR
;
470 /* Delete the remote record. */
471 int map_delete_do_remote(struct ldb_handle
*handle
)
473 struct map_context
*ac
;
475 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
477 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->remote_req
);
479 ac
->step
= MAP_DELETE_REMOTE
;
481 handle
->state
= LDB_ASYNC_INIT
;
482 handle
->status
= LDB_SUCCESS
;
484 return ldb_next_remote_request(ac
->module
, ac
->remote_req
);
487 /* Delete the local record. */
488 int map_delete_do_local(struct ldb_handle
*handle
)
490 struct map_context
*ac
;
492 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
494 /* No local record, continue remotely */
495 if (ac
->local_dn
== NULL
) {
496 return map_delete_do_remote(handle
);
499 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->local_req
);
501 ac
->step
= MAP_DELETE_LOCAL
;
503 handle
->state
= LDB_ASYNC_INIT
;
504 handle
->status
= LDB_SUCCESS
;
506 return ldb_next_request(ac
->module
, ac
->local_req
);
509 /* Delete a record. */
510 int map_delete(struct ldb_module
*module
, struct ldb_request
*req
)
512 struct ldb_handle
*h
;
513 struct map_context
*ac
;
515 /* Do not manipulate our control entries */
516 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
517 return ldb_next_request(module
, req
);
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
);
525 /* Prepare context and handle */
526 h
= map_init_handle(req
, module
);
528 return LDB_ERR_OPERATIONS_ERROR
;
530 ac
= talloc_get_type(h
->private_data
, struct map_context
);
532 /* Prepare the local operation */
533 ac
->local_req
= talloc(ac
, struct ldb_request
);
534 if (ac
->local_req
== NULL
) {
538 *(ac
->local_req
) = *req
; /* copy the request */
539 ac
->local_req
->op
.del
.dn
= req
->op
.del
.dn
;
541 ac
->local_req
->context
= NULL
;
542 ac
->local_req
->callback
= NULL
;
544 /* Prepare the remote operation */
545 ac
->remote_req
= talloc(ac
, struct ldb_request
);
546 if (ac
->remote_req
== NULL
) {
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
);
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
);
559 ac
->remote_req
->context
= NULL
;
560 ac
->remote_req
->callback
= NULL
;
562 /* Prepare the search operation */
563 ac
->search_req
= map_search_self_req(ac
, req
->op
.del
.dn
);
564 if (ac
->search_req
== NULL
) {
568 req
->handle
= h
; /* return our own handle to deal with this call */
570 ac
->step
= MAP_SEARCH_SELF_DELETE
;
572 return ldb_next_request(module
, ac
->search_req
);
578 return LDB_ERR_OPERATIONS_ERROR
;
581 /* Rename the remote record. */
582 int map_rename_do_remote(struct ldb_handle
*handle
)
584 struct map_context
*ac
;
586 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
588 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->remote_req
);
590 ac
->step
= MAP_RENAME_REMOTE
;
592 handle
->state
= LDB_ASYNC_INIT
;
593 handle
->status
= LDB_SUCCESS
;
595 return ldb_next_remote_request(ac
->module
, ac
->remote_req
);
598 /* Update the local 'IS_MAPPED' attribute. */
599 int map_rename_do_fixup(struct ldb_handle
*handle
)
601 struct map_context
*ac
;
603 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
605 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->down_req
);
607 ac
->step
= MAP_RENAME_FIXUP
;
609 handle
->state
= LDB_ASYNC_INIT
;
610 handle
->status
= LDB_SUCCESS
;
612 return ldb_next_request(ac
->module
, ac
->down_req
);
615 /* Rename the local record. */
616 int map_rename_do_local(struct ldb_handle
*handle
)
618 struct map_context
*ac
;
620 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
622 /* No local record, continue remotely */
623 if (ac
->local_dn
== NULL
) {
624 return map_rename_do_remote(handle
);
627 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->local_req
);
629 ac
->step
= MAP_RENAME_LOCAL
;
631 handle
->state
= LDB_ASYNC_INIT
;
632 handle
->status
= LDB_SUCCESS
;
634 return ldb_next_request(ac
->module
, ac
->local_req
);
637 /* Rename a record. */
638 int map_rename(struct ldb_module
*module
, struct ldb_request
*req
)
640 struct ldb_handle
*h
;
641 struct map_context
*ac
;
643 /* Do not manipulate our control entries */
644 if (ldb_dn_is_special(req
->op
.rename
.olddn
)) {
645 return ldb_next_request(module
, req
);
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
);
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
;
660 /* Prepare context and handle */
661 h
= map_init_handle(req
, module
);
663 return LDB_ERR_OPERATIONS_ERROR
;
665 ac
= talloc_get_type(h
->private_data
, struct map_context
);
667 /* Prepare the local operation */
668 ac
->local_req
= talloc(ac
, struct ldb_request
);
669 if (ac
->local_req
== NULL
) {
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
;
677 ac
->local_req
->context
= NULL
;
678 ac
->local_req
->callback
= NULL
;
680 /* Prepare the remote operation */
681 ac
->remote_req
= talloc(ac
, struct ldb_request
);
682 if (ac
->remote_req
== NULL
) {
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
);
690 ac
->remote_req
->context
= NULL
;
691 ac
->remote_req
->callback
= NULL
;
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
);
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
) {
706 /* Prepare the search operation */
707 ac
->search_req
= map_search_self_req(ac
, req
->op
.rename
.olddn
);
708 if (ac
->search_req
== NULL
) {
712 req
->handle
= h
; /* return our own handle to deal with this call */
714 ac
->step
= MAP_SEARCH_SELF_RENAME
;
716 return ldb_next_request(module
, ac
->search_req
);
722 return LDB_ERR_OPERATIONS_ERROR
;