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 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.
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
;
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 /* 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
);
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
;
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
);
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
) {
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
) {
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
);
279 /* Prepare the remote message */
280 remote
= ldb_msg_new(ac
->remote_req
);
281 if (remote
== NULL
) {
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) {
305 req
->handle
= h
; /* return our own handle to deal with this call */
306 return map_add_do_local(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
;
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
);
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
) {
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
) {
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
);
434 /* Prepare the remote message */
435 remote
= ldb_msg_new(ac
->remote_req
);
436 if (remote
== NULL
) {
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
) {
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
);
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
);
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
) {
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
) {
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
) {
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
);
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
);
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
) {
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
) {
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
) {
707 /* Prepare the search operation */
708 ac
->search_req
= map_search_self_req(ac
, req
->op
.rename
.olddn
);
709 if (ac
->search_req
== NULL
) {
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
);
723 return LDB_ERR_OPERATIONS_ERROR
;