2 ldb database mapping module
4 Copyright (C) Jelmer Vernooij 2005
5 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 * NOTICE: this module is NOT released under the GNU LGPL license as
9 * other ldb code. This module is release under the GNU GPL v2 or
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program 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
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include "ldb/include/includes.h"
30 #include "ldb/modules/ldb_map.h"
31 #include "ldb/modules/ldb_map_private.h"
35 * ================== */
37 /* Select attributes that stay in the local partition. */
38 static const char **map_attrs_select_local(struct ldb_module
*module
, void *mem_ctx
, const char * const *attrs
)
40 const struct ldb_map_context
*data
= map_get_context(module
);
48 result
= talloc_array(mem_ctx
, const char *, 1);
54 for (i
= 0; attrs
[i
]; i
++) {
55 /* Wildcards and ignored attributes are kept locally */
56 if ((ldb_attr_cmp(attrs
[i
], "*") == 0) ||
57 (!map_attr_check_remote(data
, attrs
[i
]))) {
58 result
= talloc_realloc(mem_ctx
, result
, const char *, last
+2);
63 result
[last
] = talloc_strdup(result
, attrs
[i
]);
64 result
[last
+1] = NULL
;
77 /* Collect attributes that are mapped into the remote partition. */
78 static const char **map_attrs_collect_remote(struct ldb_module
*module
, void *mem_ctx
,
79 const char * const *attrs
)
81 const struct ldb_map_context
*data
= map_get_context(module
);
83 const struct ldb_map_attribute
*map
;
84 const char *name
=NULL
;
89 result
= talloc_array(mem_ctx
, const char *, 1);
95 for (i
= 0; attrs
[i
]; i
++) {
96 /* Wildcards are kept remotely, too */
97 if (ldb_attr_cmp(attrs
[i
], "*") == 0) {
98 const char **new_attrs
= NULL
;
99 ret
= map_attrs_merge(module
, mem_ctx
, &new_attrs
, attrs
);
100 if (ret
!= LDB_SUCCESS
) {
103 ret
= map_attrs_merge(module
, mem_ctx
, &new_attrs
, data
->wildcard_attributes
);
104 if (ret
!= LDB_SUCCESS
) {
113 for (i
= 0; attrs
[i
]; i
++) {
114 /* Wildcards are kept remotely, too */
115 if (ldb_attr_cmp(attrs
[i
], "*") == 0) {
116 /* Add all 'include in wildcard' attributes */
121 /* Add remote names of mapped attrs */
122 map
= map_attr_find_local(data
, attrs
[i
]);
137 name
= map
->u
.rename
.remote_name
;
141 /* Add all remote names of "generate" attrs */
142 for (j
= 0; map
->u
.generate
.remote_names
[j
]; j
++) {
143 result
= talloc_realloc(mem_ctx
, result
, const char *, last
+2);
144 if (result
== NULL
) {
148 result
[last
] = talloc_strdup(result
, map
->u
.generate
.remote_names
[j
]);
149 result
[last
+1] = NULL
;
155 named
: /* We found a single remote name, add that */
156 result
= talloc_realloc(mem_ctx
, result
, const char *, last
+2);
157 if (result
== NULL
) {
161 result
[last
] = talloc_strdup(result
, name
);
162 result
[last
+1] = NULL
;
174 /* Split attributes that stay in the local partition from those that
175 * are mapped into the remote partition. */
176 static int map_attrs_partition(struct ldb_module
*module
, void *mem_ctx
, const char ***local_attrs
, const char ***remote_attrs
, const char * const *attrs
)
178 *local_attrs
= map_attrs_select_local(module
, mem_ctx
, attrs
);
179 *remote_attrs
= map_attrs_collect_remote(module
, mem_ctx
, attrs
);
184 /* Mapping message elements
185 * ======================== */
187 /* Add an element to a message, overwriting any old identically named elements. */
188 static int ldb_msg_replace(struct ldb_message
*msg
, const struct ldb_message_element
*el
)
190 struct ldb_message_element
*old
;
192 old
= ldb_msg_find_element(msg
, el
->name
);
194 /* no local result, add as new element */
196 if (ldb_msg_add_empty(msg
, el
->name
, 0, &old
) != 0) {
199 talloc_free(old
->name
);
202 /* copy new element */
205 /* and make sure we reference the contents */
206 if (!talloc_reference(msg
->elements
, el
->name
)) {
209 if (!talloc_reference(msg
->elements
, el
->values
)) {
216 /* Map a message element back into the local partition. */
217 static struct ldb_message_element
*ldb_msg_el_map_remote(struct ldb_module
*module
,
219 const struct ldb_map_attribute
*map
,
220 const char *attr_name
,
221 const struct ldb_message_element
*old
)
223 struct ldb_message_element
*el
;
226 el
= talloc_zero(mem_ctx
, struct ldb_message_element
);
232 el
->num_values
= old
->num_values
;
233 el
->values
= talloc_array(el
, struct ldb_val
, el
->num_values
);
234 if (el
->values
== NULL
) {
240 el
->name
= talloc_strdup(el
, attr_name
);
241 if (el
->name
== NULL
) {
247 for (i
= 0; i
< el
->num_values
; i
++) {
248 el
->values
[i
] = ldb_val_map_remote(module
, el
->values
, map
, &old
->values
[i
]);
254 /* Merge a remote message element into a local message. */
255 static int ldb_msg_el_merge(struct ldb_module
*module
, struct ldb_message
*local
,
256 struct ldb_message
*remote
, const char *attr_name
)
258 const struct ldb_map_context
*data
= map_get_context(module
);
259 const struct ldb_map_attribute
*map
;
260 struct ldb_message_element
*old
, *el
=NULL
;
261 const char *remote_name
= NULL
;
263 /* We handle wildcards in ldb_msg_el_merge_wildcard */
264 if (ldb_attr_cmp(attr_name
, "*") == 0) {
268 map
= map_attr_find_local(data
, attr_name
);
270 /* Unknown attribute in remote message:
271 * skip, attribute was probably auto-generated */
280 remote_name
= map
->u
.convert
.remote_name
;
283 remote_name
= attr_name
;
286 remote_name
= map
->u
.rename
.remote_name
;
297 if (map
->u
.convert
.convert_remote
== NULL
) {
298 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
299 "Skipping attribute '%s': "
300 "'convert_remote' not set\n",
307 old
= ldb_msg_find_element(remote
, remote_name
);
309 el
= ldb_msg_el_map_remote(module
, local
, map
, attr_name
, old
);
311 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
316 if (map
->u
.generate
.generate_local
== NULL
) {
317 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
318 "Skipping attribute '%s': "
319 "'generate_local' not set\n",
324 el
= map
->u
.generate
.generate_local(module
, local
, attr_name
, remote
);
326 /* Generation failure is probably due to lack of source attributes */
327 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
333 return LDB_ERR_OPERATIONS_ERROR
;
336 return ldb_msg_replace(local
, el
);
339 /* Handle wildcard parts of merging a remote message element into a local message. */
340 static int ldb_msg_el_merge_wildcard(struct ldb_module
*module
, struct ldb_message
*local
,
341 struct ldb_message
*remote
)
343 const struct ldb_map_context
*data
= map_get_context(module
);
344 const struct ldb_map_attribute
*map
= map_attr_find_local(data
, "*");
345 struct ldb_message_element
*el
=NULL
;
348 /* Perhaps we have a mapping for "*" */
349 if (map
&& map
->type
== MAP_KEEP
) {
350 /* We copy everything over, and hope that anything with a
351 more specific rule is overwritten */
352 for (i
= 0; i
< remote
->num_elements
; i
++) {
353 el
= ldb_msg_el_map_remote(module
, local
, map
, remote
->elements
[i
].name
,
354 &remote
->elements
[i
]);
356 return LDB_ERR_OPERATIONS_ERROR
;
359 ret
= ldb_msg_replace(local
, el
);
366 /* Now walk the list of possible mappings, and apply each */
367 for (i
= 0; data
->attribute_maps
[i
].local_name
; i
++) {
368 ret
= ldb_msg_el_merge(module
, local
, remote
,
369 data
->attribute_maps
[i
].local_name
);
370 if (ret
== LDB_ERR_NO_SUCH_ATTRIBUTE
) {
383 * ================ */
385 /* Merge two local messages into a single one. */
386 static int ldb_msg_merge_local(struct ldb_module
*module
, struct ldb_message
*msg1
, struct ldb_message
*msg2
)
390 for (i
= 0; i
< msg2
->num_elements
; i
++) {
391 ret
= ldb_msg_replace(msg1
, &msg2
->elements
[i
]);
400 /* Merge a local and a remote message into a single local one. */
401 static int ldb_msg_merge_remote(struct map_context
*ac
, struct ldb_message
*local
,
402 struct ldb_message
*remote
)
405 const char * const *attrs
= ac
->all_attrs
;
407 ret
= ldb_msg_el_merge_wildcard(ac
->module
, local
, remote
);
413 for (i
= 0; attrs
&& attrs
[i
]; i
++) {
414 if (ldb_attr_cmp(attrs
[i
], "*") == 0) {
415 ret
= ldb_msg_el_merge_wildcard(ac
->module
, local
, remote
);
423 /* Try to map each attribute back;
424 * Add to local message is possible,
425 * Overwrite old local attribute if necessary */
426 for (i
= 0; attrs
&& attrs
[i
]; i
++) {
427 ret
= ldb_msg_el_merge(ac
->module
, local
, remote
,
429 if (ret
== LDB_ERR_NO_SUCH_ATTRIBUTE
) {
438 /* Mapping search results
439 * ====================== */
441 /* Map a search result back into the local partition. */
442 static int map_reply_remote(struct map_context
*ac
, struct ldb_reply
*ares
)
444 struct ldb_message
*msg
;
448 /* There is no result message, skip */
449 if (ares
->type
!= LDB_REPLY_ENTRY
) {
453 /* Create a new result message */
454 msg
= ldb_msg_new(ares
);
460 /* Merge remote message into new message */
461 ret
= ldb_msg_merge_remote(ac
, msg
, ares
->message
);
467 /* Create corresponding local DN */
468 dn
= ldb_dn_map_rebase_remote(ac
->module
, msg
, ares
->message
->dn
);
475 /* Store new message with new DN as the result */
476 talloc_free(ares
->message
);
482 /* Mapping parse trees
483 * =================== */
485 /* Check whether a parse tree can safely be split in two. */
486 static BOOL
ldb_parse_tree_check_splittable(const struct ldb_parse_tree
*tree
)
488 const struct ldb_parse_tree
*subtree
= tree
;
492 switch (subtree
->operation
) {
495 subtree
= subtree
->u
.isnot
.child
;
499 return !negate
; /* if negate: False */
502 return negate
; /* if negate: True */
505 return True
; /* simple parse tree */
509 return True
; /* no parse tree */
512 /* Collect a list of attributes required to match a given parse tree. */
513 static int ldb_parse_tree_collect_attrs(struct ldb_module
*module
, void *mem_ctx
, const char ***attrs
, const struct ldb_parse_tree
*tree
)
515 const char **new_attrs
;
522 switch (tree
->operation
) {
524 case LDB_OP_AND
: /* attributes stored in list of subtrees */
525 for (i
= 0; i
< tree
->u
.list
.num_elements
; i
++) {
526 ret
= ldb_parse_tree_collect_attrs(module
, mem_ctx
,
527 attrs
, tree
->u
.list
.elements
[i
]);
534 case LDB_OP_NOT
: /* attributes stored in single subtree */
535 return ldb_parse_tree_collect_attrs(module
, mem_ctx
, attrs
, tree
->u
.isnot
.child
);
537 default: /* single attribute in tree */
538 new_attrs
= ldb_attr_list_copy_add(mem_ctx
, *attrs
, tree
->u
.equality
.attr
);
547 static int map_subtree_select_local(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
);
549 /* Select a negated subtree that queries attributes in the local partition */
550 static int map_subtree_select_local_not(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
552 struct ldb_parse_tree
*child
;
555 /* Prepare new tree */
556 *new = talloc_memdup(mem_ctx
, tree
, sizeof(struct ldb_parse_tree
));
562 /* Generate new subtree */
563 ret
= map_subtree_select_local(module
, *new, &child
, tree
->u
.isnot
.child
);
569 /* Prune tree without subtree */
576 (*new)->u
.isnot
.child
= child
;
581 /* Select a list of subtrees that query attributes in the local partition */
582 static int map_subtree_select_local_list(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
586 /* Prepare new tree */
587 *new = talloc_memdup(mem_ctx
, tree
, sizeof(struct ldb_parse_tree
));
593 /* Prepare list of subtrees */
594 (*new)->u
.list
.num_elements
= 0;
595 (*new)->u
.list
.elements
= talloc_array(*new, struct ldb_parse_tree
*, tree
->u
.list
.num_elements
);
596 if ((*new)->u
.list
.elements
== NULL
) {
602 /* Generate new list of subtrees */
604 for (i
= 0; i
< tree
->u
.list
.num_elements
; i
++) {
605 struct ldb_parse_tree
*child
;
606 ret
= map_subtree_select_local(module
, *new, &child
, tree
->u
.list
.elements
[i
]);
613 (*new)->u
.list
.elements
[j
] = child
;
618 /* Prune tree without subtrees */
625 /* Fix subtree list size */
626 (*new)->u
.list
.num_elements
= j
;
627 (*new)->u
.list
.elements
= talloc_realloc(*new, (*new)->u
.list
.elements
, struct ldb_parse_tree
*, (*new)->u
.list
.num_elements
);
632 /* Select a simple subtree that queries attributes in the local partition */
633 static int map_subtree_select_local_simple(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
635 /* Prepare new tree */
636 *new = talloc_memdup(mem_ctx
, tree
, sizeof(struct ldb_parse_tree
));
645 /* Select subtrees that query attributes in the local partition */
646 static int map_subtree_select_local(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
648 const struct ldb_map_context
*data
= map_get_context(module
);
654 if (tree
->operation
== LDB_OP_NOT
) {
655 return map_subtree_select_local_not(module
, mem_ctx
, new, tree
);
658 if (tree
->operation
== LDB_OP_AND
|| tree
->operation
== LDB_OP_OR
) {
659 return map_subtree_select_local_list(module
, mem_ctx
, new, tree
);
662 if (map_attr_check_remote(data
, tree
->u
.equality
.attr
)) {
667 return map_subtree_select_local_simple(module
, mem_ctx
, new, tree
);
670 static int map_subtree_collect_remote(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
);
672 /* Collect a negated subtree that queries attributes in the remote partition */
673 static int map_subtree_collect_remote_not(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
675 struct ldb_parse_tree
*child
;
678 /* Prepare new tree */
679 *new = talloc_memdup(mem_ctx
, tree
, sizeof(struct ldb_parse_tree
));
685 /* Generate new subtree */
686 ret
= map_subtree_collect_remote(module
, *new, &child
, tree
->u
.isnot
.child
);
692 /* Prune tree without subtree */
699 (*new)->u
.isnot
.child
= child
;
704 /* Collect a list of subtrees that query attributes in the remote partition */
705 static int map_subtree_collect_remote_list(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
709 /* Prepare new tree */
710 *new = talloc_memdup(mem_ctx
, tree
, sizeof(struct ldb_parse_tree
));
716 /* Prepare list of subtrees */
717 (*new)->u
.list
.num_elements
= 0;
718 (*new)->u
.list
.elements
= talloc_array(*new, struct ldb_parse_tree
*, tree
->u
.list
.num_elements
);
719 if ((*new)->u
.list
.elements
== NULL
) {
725 /* Generate new list of subtrees */
727 for (i
= 0; i
< tree
->u
.list
.num_elements
; i
++) {
728 struct ldb_parse_tree
*child
;
729 ret
= map_subtree_collect_remote(module
, *new, &child
, tree
->u
.list
.elements
[i
]);
736 (*new)->u
.list
.elements
[j
] = child
;
741 /* Prune tree without subtrees */
748 /* Fix subtree list size */
749 (*new)->u
.list
.num_elements
= j
;
750 (*new)->u
.list
.elements
= talloc_realloc(*new, (*new)->u
.list
.elements
, struct ldb_parse_tree
*, (*new)->u
.list
.num_elements
);
755 /* Collect a simple subtree that queries attributes in the remote partition */
756 int map_subtree_collect_remote_simple(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
, const struct ldb_map_attribute
*map
)
760 /* Prepare new tree */
761 *new = talloc(mem_ctx
, struct ldb_parse_tree
);
768 if (map
->type
== MAP_KEEP
) {
769 /* Nothing to do here */
773 /* Store attribute and value in new tree */
774 switch (tree
->operation
) {
776 attr
= map_attr_map_local(*new, map
, tree
->u
.present
.attr
);
777 (*new)->u
.present
.attr
= attr
;
779 case LDB_OP_SUBSTRING
:
781 attr
= map_attr_map_local(*new, map
, tree
->u
.substring
.attr
);
782 (*new)->u
.substring
.attr
= attr
;
785 case LDB_OP_EQUALITY
:
786 attr
= map_attr_map_local(*new, map
, tree
->u
.equality
.attr
);
787 (*new)->u
.equality
.attr
= attr
;
792 attr
= map_attr_map_local(*new, map
, tree
->u
.comparison
.attr
);
793 (*new)->u
.comparison
.attr
= attr
;
795 case LDB_OP_EXTENDED
:
796 attr
= map_attr_map_local(*new, map
, tree
->u
.extended
.attr
);
797 (*new)->u
.extended
.attr
= attr
;
799 default: /* unknown kind of simple subtree */
810 if (map
->type
== MAP_RENAME
) {
811 /* Nothing more to do here, the attribute has been renamed */
815 /* Store attribute and value in new tree */
816 switch (tree
->operation
) {
819 case LDB_OP_SUBSTRING
:
823 (*new)->u
.substring
.chunks
= NULL
;
824 for (i
=0; tree
->u
.substring
.chunks
[i
]; i
++) {
825 (*new)->u
.substring
.chunks
= talloc_realloc(*new, (*new)->u
.substring
.chunks
, struct ldb_val
*, i
+2);
826 if (!(*new)->u
.substring
.chunks
) {
831 (*new)->u
.substring
.chunks
[i
] = talloc(*new, struct ldb_val
);
832 if (!(*new)->u
.substring
.chunks
[i
]) {
837 *(*new)->u
.substring
.chunks
[i
] = ldb_val_map_local(module
, *new, map
, tree
->u
.substring
.chunks
[i
]);
838 (*new)->u
.substring
.chunks
[i
+1] = NULL
;
842 case LDB_OP_EQUALITY
:
843 (*new)->u
.equality
.value
= ldb_val_map_local(module
, *new, map
, &tree
->u
.equality
.value
);
848 (*new)->u
.comparison
.value
= ldb_val_map_local(module
, *new, map
, &tree
->u
.comparison
.value
);
850 case LDB_OP_EXTENDED
:
851 (*new)->u
.extended
.value
= ldb_val_map_local(module
, *new, map
, &tree
->u
.extended
.value
);
852 (*new)->u
.extended
.rule_id
= talloc_strdup(*new, tree
->u
.extended
.rule_id
);
854 default: /* unknown kind of simple subtree */
862 /* Collect subtrees that query attributes in the remote partition */
863 static int map_subtree_collect_remote(struct ldb_module
*module
, void *mem_ctx
, struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
865 const struct ldb_map_context
*data
= map_get_context(module
);
866 const struct ldb_map_attribute
*map
;
872 if (tree
->operation
== LDB_OP_NOT
) {
873 return map_subtree_collect_remote_not(module
, mem_ctx
, new, tree
);
876 if ((tree
->operation
== LDB_OP_AND
) || (tree
->operation
== LDB_OP_OR
)) {
877 return map_subtree_collect_remote_list(module
, mem_ctx
, new, tree
);
880 if (!map_attr_check_remote(data
, tree
->u
.equality
.attr
)) {
885 map
= map_attr_find_local(data
, tree
->u
.equality
.attr
);
886 if (map
->convert_operator
) {
887 return map
->convert_operator(module
, mem_ctx
, new, tree
);
890 if (map
->type
== MAP_GENERATE
) {
891 ldb_debug(module
->ldb
, LDB_DEBUG_WARNING
, "ldb_map: "
892 "Skipping attribute '%s': "
893 "'convert_operator' not set\n",
894 tree
->u
.equality
.attr
);
899 return map_subtree_collect_remote_simple(module
, mem_ctx
, new, tree
, map
);
902 /* Split subtrees that query attributes in the local partition from
903 * those that query the remote partition. */
904 static int ldb_parse_tree_partition(struct ldb_module
*module
, void *local_ctx
, void *remote_ctx
, struct ldb_parse_tree
**local_tree
, struct ldb_parse_tree
**remote_tree
, const struct ldb_parse_tree
*tree
)
911 /* No original tree */
916 /* Generate local tree */
917 ret
= map_subtree_select_local(module
, local_ctx
, local_tree
, tree
);
922 /* Generate remote tree */
923 ret
= map_subtree_collect_remote(module
, remote_ctx
, remote_tree
, tree
);
925 talloc_free(*local_tree
);
932 /* Collect a list of attributes required either explicitly from a
933 * given list or implicitly from a given parse tree; split the
934 * collected list into local and remote parts. */
935 static int map_attrs_collect_and_partition(struct ldb_module
*module
, struct map_context
*ac
,
936 const char * const *search_attrs
,
937 const struct ldb_parse_tree
*tree
)
940 const char **tree_attrs
;
941 const char **remote_attrs
;
942 const char **local_attrs
;
945 /* Clear initial lists of partitioned attributes */
947 /* Clear initial lists of partitioned attributes */
949 /* There is no tree, just partition the searched attributes */
951 ret
= map_attrs_partition(module
, ac
,
952 &local_attrs
, &remote_attrs
, search_attrs
);
954 ac
->local_attrs
= local_attrs
;
955 ac
->remote_attrs
= remote_attrs
;
956 ac
->all_attrs
= search_attrs
;
961 /* Create context for temporary memory */
962 tmp_ctx
= talloc_new(ac
);
963 if (tmp_ctx
== NULL
) {
967 /* Prepare list of attributes from tree */
968 tree_attrs
= talloc_array(tmp_ctx
, const char *, 1);
969 if (tree_attrs
== NULL
) {
970 talloc_free(tmp_ctx
);
973 tree_attrs
[0] = NULL
;
975 /* Collect attributes from tree */
976 ret
= ldb_parse_tree_collect_attrs(module
, tmp_ctx
, &tree_attrs
, tree
);
981 /* Merge attributes from search operation */
982 ret
= map_attrs_merge(module
, tmp_ctx
, &tree_attrs
, search_attrs
);
987 /* Split local from remote attributes */
988 ret
= map_attrs_partition(module
, ac
, &local_attrs
,
989 &remote_attrs
, tree_attrs
);
992 ac
->local_attrs
= local_attrs
;
993 ac
->remote_attrs
= remote_attrs
;
994 talloc_steal(ac
, tree_attrs
);
995 ac
->all_attrs
= tree_attrs
;
998 /* Free temporary memory */
999 talloc_free(tmp_ctx
);
1008 /* Outbound requests: search
1009 * ========================= */
1011 /* Pass a merged search result up the callback chain. */
1012 int map_up_callback(struct ldb_context
*ldb
, const struct ldb_request
*req
, struct ldb_reply
*ares
)
1016 /* No callback registered, stop */
1017 if (req
->callback
== NULL
) {
1021 /* Only records need special treatment */
1022 if (ares
->type
!= LDB_REPLY_ENTRY
) {
1023 return req
->callback(ldb
, req
->context
, ares
);
1026 /* Merged result doesn't match original query, skip */
1027 if (!ldb_match_msg(ldb
, ares
->message
, req
->op
.search
.tree
, req
->op
.search
.base
, req
->op
.search
.scope
)) {
1028 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "ldb_map: "
1029 "Skipping record '%s': "
1030 "doesn't match original search\n",
1031 ldb_dn_linearize(ldb
, ares
->message
->dn
));
1035 /* Limit result to requested attrs */
1036 if ((req
->op
.search
.attrs
) && (!ldb_attr_in_list(req
->op
.search
.attrs
, "*"))) {
1037 for (i
= 0; i
< ares
->message
->num_elements
; ) {
1038 struct ldb_message_element
*el
= &ares
->message
->elements
[i
];
1039 if (!ldb_attr_in_list(req
->op
.search
.attrs
, el
->name
)) {
1040 ldb_msg_remove_element(ares
->message
, el
);
1047 return req
->callback(ldb
, req
->context
, ares
);
1050 /* Merge the remote and local parts of a search result. */
1051 int map_local_merge_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
1053 struct map_search_context
*sc
;
1056 if (context
== NULL
|| ares
== NULL
) {
1057 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "ldb_map: "
1058 "NULL Context or Result in `map_local_merge_callback`"));
1059 return LDB_ERR_OPERATIONS_ERROR
;
1062 sc
= talloc_get_type(context
, struct map_search_context
);
1064 switch (ares
->type
) {
1065 case LDB_REPLY_ENTRY
:
1066 /* We have already found a local record */
1067 if (sc
->local_res
) {
1068 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "ldb_map: "
1069 "Too many results to base search for local entry"));
1071 return LDB_ERR_OPERATIONS_ERROR
;
1074 /* Store local result */
1075 sc
->local_res
= ares
;
1077 /* Merge remote into local message */
1078 ret
= ldb_msg_merge_local(sc
->ac
->module
, ares
->message
, sc
->remote_res
->message
);
1081 return LDB_ERR_OPERATIONS_ERROR
;
1084 return map_up_callback(ldb
, sc
->ac
->orig_req
, ares
);
1086 case LDB_REPLY_DONE
:
1087 /* No local record found, continue with remote record */
1088 if (sc
->local_res
== NULL
) {
1089 return map_up_callback(ldb
, sc
->ac
->orig_req
, sc
->remote_res
);
1094 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "ldb_map: "
1095 "Unexpected result type in base search for local entry"));
1097 return LDB_ERR_OPERATIONS_ERROR
;
1101 /* Search the local part of a remote search result. */
1102 int map_remote_search_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
1104 struct map_context
*ac
;
1105 struct map_search_context
*sc
;
1106 struct ldb_request
*req
;
1109 if (context
== NULL
|| ares
== NULL
) {
1110 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "ldb_map: "
1111 "NULL Context or Result in `map_remote_search_callback`"));
1112 return LDB_ERR_OPERATIONS_ERROR
;
1115 ac
= talloc_get_type(context
, struct map_context
);
1117 /* It's not a record, stop searching */
1118 if (ares
->type
!= LDB_REPLY_ENTRY
) {
1119 return map_up_callback(ldb
, ac
->orig_req
, ares
);
1122 /* Map result record into a local message */
1123 ret
= map_reply_remote(ac
, ares
);
1126 return LDB_ERR_OPERATIONS_ERROR
;
1129 /* There is no local db, stop searching */
1130 if (!map_check_local_db(ac
->module
)) {
1131 return map_up_callback(ldb
, ac
->orig_req
, ares
);
1134 /* Prepare local search context */
1135 sc
= map_init_search_context(ac
, ares
);
1138 return LDB_ERR_OPERATIONS_ERROR
;
1141 /* Prepare local search request */
1142 /* TODO: use GUIDs here instead? */
1144 ac
->search_reqs
= talloc_realloc(ac
, ac
->search_reqs
, struct ldb_request
*, ac
->num_searches
+ 2);
1145 if (ac
->search_reqs
== NULL
) {
1147 return LDB_ERR_OPERATIONS_ERROR
;
1150 ac
->search_reqs
[ac
->num_searches
]
1151 = req
= map_search_base_req(ac
, ares
->message
->dn
,
1152 NULL
, NULL
, sc
, map_local_merge_callback
);
1156 return LDB_ERR_OPERATIONS_ERROR
;
1159 ac
->search_reqs
[ac
->num_searches
] = NULL
;
1161 return ldb_next_request(ac
->module
, req
);
1164 /* Search a record. */
1165 int map_search(struct ldb_module
*module
, struct ldb_request
*req
)
1167 struct ldb_handle
*h
;
1168 struct map_context
*ac
;
1169 struct ldb_parse_tree
*local_tree
, *remote_tree
;
1172 const char *wildcard
[] = { "*", NULL
};
1173 const char * const *attrs
;
1175 /* Do not manipulate our control entries */
1176 if (ldb_dn_is_special(req
->op
.search
.base
))
1177 return ldb_next_request(module
, req
);
1179 /* No mapping requested, skip to next module */
1180 if ((req
->op
.search
.base
) && (!ldb_dn_check_local(module
, req
->op
.search
.base
))) {
1181 return ldb_next_request(module
, req
);
1184 /* TODO: How can we be sure about which partition we are
1185 * targetting when there is no search base? */
1187 /* Prepare context and handle */
1188 h
= map_init_handle(req
, module
);
1190 return LDB_ERR_OPERATIONS_ERROR
;
1192 ac
= talloc_get_type(h
->private_data
, struct map_context
);
1194 ac
->search_reqs
= talloc_array(ac
, struct ldb_request
*, 2);
1195 if (ac
->search_reqs
== NULL
) {
1197 return LDB_ERR_OPERATIONS_ERROR
;
1199 ac
->num_searches
= 1;
1200 ac
->search_reqs
[1] = NULL
;
1202 /* Prepare the remote operation */
1203 ac
->search_reqs
[0] = talloc(ac
, struct ldb_request
);
1204 if (ac
->search_reqs
[0] == NULL
) {
1208 *(ac
->search_reqs
[0]) = *req
; /* copy the request */
1210 ac
->search_reqs
[0]->handle
= h
; /* return our own handle to deal with this call */
1212 ac
->search_reqs
[0]->context
= ac
;
1213 ac
->search_reqs
[0]->callback
= map_remote_search_callback
;
1215 /* It is easier to deal with the two different ways of
1216 * expressing the wildcard in the same codepath */
1217 attrs
= req
->op
.search
.attrs
;
1218 if (attrs
== NULL
) {
1222 /* Split local from remote attrs */
1223 ret
= map_attrs_collect_and_partition(module
, ac
,
1224 attrs
, req
->op
.search
.tree
);
1229 ac
->search_reqs
[0]->op
.search
.attrs
= ac
->remote_attrs
;
1231 /* Split local from remote tree */
1232 ret
= ldb_parse_tree_partition(module
, ac
, ac
->search_reqs
[0],
1233 &local_tree
, &remote_tree
,
1234 req
->op
.search
.tree
);
1239 if (((local_tree
!= NULL
) && (remote_tree
!= NULL
)) &&
1240 (!ldb_parse_tree_check_splittable(req
->op
.search
.tree
))) {
1241 /* The query can't safely be split, enumerate the remote partition */
1246 if (local_tree
== NULL
) {
1247 /* Construct default local parse tree */
1248 local_tree
= talloc_zero(ac
, struct ldb_parse_tree
);
1249 if (local_tree
== NULL
) {
1250 map_oom(ac
->module
);
1254 local_tree
->operation
= LDB_OP_PRESENT
;
1255 local_tree
->u
.present
.attr
= talloc_strdup(local_tree
, IS_MAPPED
);
1257 if (remote_tree
== NULL
) {
1258 /* Construct default remote parse tree */
1259 remote_tree
= ldb_parse_tree(ac
->search_reqs
[0], NULL
);
1260 if (remote_tree
== NULL
) {
1265 ac
->local_tree
= local_tree
;
1266 ac
->search_reqs
[0]->op
.search
.tree
= remote_tree
;
1268 ldb_set_timeout_from_prev_req(module
->ldb
, req
, ac
->search_reqs
[0]);
1270 h
->state
= LDB_ASYNC_INIT
;
1271 h
->status
= LDB_SUCCESS
;
1273 ac
->step
= MAP_SEARCH_REMOTE
;
1275 ret
= ldb_next_remote_request(module
, ac
->search_reqs
[0]);
1276 if (ret
== LDB_SUCCESS
) {
1285 return LDB_ERR_OPERATIONS_ERROR
;