LDB:map - make LDB "signed-safe" on counter variables where appropriate
[Samba/ekacnet.git] / source4 / lib / ldb / ldb_map / ldb_map_outbound.c
blob836aec9b1bd7d2862f166e56ffc7cd8bb06ff0ad
1 /*
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
7 Copyright (C) Simo Sorce <idra@samba.org> 2008
9 ** NOTE! The following LGPL license applies to the ldb
10 ** library. This does NOT imply that all of Samba is released
11 ** under the LGPL
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 3 of the License, or (at your option) any later version.
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, see <http://www.gnu.org/licenses/>.
28 #include "ldb_includes.h"
29 #include "ldb_map.h"
30 #include "ldb_map_private.h"
33 /* Mapping attributes
34 * ================== */
36 /* Select attributes that stay in the local partition. */
37 static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
39 const struct ldb_map_context *data = map_get_context(module);
40 const char **result;
41 unsigned int i, last;
43 if (attrs == NULL)
44 return NULL;
46 last = 0;
47 result = talloc_array(mem_ctx, const char *, 1);
48 if (result == NULL) {
49 goto failed;
51 result[0] = NULL;
53 for (i = 0; attrs[i]; i++) {
54 /* Wildcards and ignored attributes are kept locally */
55 if ((ldb_attr_cmp(attrs[i], "*") == 0) ||
56 (!map_attr_check_remote(data, attrs[i]))) {
57 result = talloc_realloc(mem_ctx, result, const char *, last+2);
58 if (result == NULL) {
59 goto failed;
62 result[last] = talloc_strdup(result, attrs[i]);
63 result[last+1] = NULL;
64 last++;
68 return result;
70 failed:
71 talloc_free(result);
72 map_oom(module);
73 return NULL;
76 /* Collect attributes that are mapped into the remote partition. */
77 static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx,
78 const char * const *attrs)
80 const struct ldb_map_context *data = map_get_context(module);
81 const char **result;
82 const struct ldb_map_attribute *map;
83 const char *name=NULL;
84 unsigned int i, j, last;
85 int ret;
87 last = 0;
88 result = talloc_array(mem_ctx, const char *, 1);
89 if (result == NULL) {
90 goto failed;
92 result[0] = NULL;
94 for (i = 0; attrs[i]; i++) {
95 /* Wildcards are kept remotely, too */
96 if (ldb_attr_cmp(attrs[i], "*") == 0) {
97 const char **new_attrs = NULL;
98 ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs);
99 if (ret != LDB_SUCCESS) {
100 goto failed;
102 ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
103 if (ret != LDB_SUCCESS) {
104 goto failed;
107 attrs = new_attrs;
108 break;
112 for (i = 0; attrs[i]; i++) {
113 /* Wildcards are kept remotely, too */
114 if (ldb_attr_cmp(attrs[i], "*") == 0) {
115 /* Add all 'include in wildcard' attributes */
116 name = attrs[i];
117 goto named;
120 /* Add remote names of mapped attrs */
121 map = map_attr_find_local(data, attrs[i]);
122 if (map == NULL) {
123 continue;
126 switch (map->type) {
127 case LDB_MAP_IGNORE:
128 continue;
130 case LDB_MAP_KEEP:
131 name = attrs[i];
132 goto named;
134 case LDB_MAP_RENAME:
135 case LDB_MAP_CONVERT:
136 name = map->u.rename.remote_name;
137 goto named;
139 case LDB_MAP_GENERATE:
140 /* Add all remote names of "generate" attrs */
141 for (j = 0; map->u.generate.remote_names[j]; j++) {
142 result = talloc_realloc(mem_ctx, result, const char *, last+2);
143 if (result == NULL) {
144 goto failed;
147 result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
148 result[last+1] = NULL;
149 last++;
151 continue;
154 named: /* We found a single remote name, add that */
155 result = talloc_realloc(mem_ctx, result, const char *, last+2);
156 if (result == NULL) {
157 goto failed;
160 result[last] = talloc_strdup(result, name);
161 result[last+1] = NULL;
162 last++;
165 return result;
167 failed:
168 talloc_free(result);
169 map_oom(module);
170 return NULL;
173 /* Split attributes that stay in the local partition from those that
174 * are mapped into the remote partition. */
175 static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs)
177 *local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
178 *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs);
180 return 0;
183 /* Mapping message elements
184 * ======================== */
186 /* Add an element to a message, overwriting any old identically named elements. */
187 static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
189 struct ldb_message_element *old;
191 old = ldb_msg_find_element(msg, el->name);
193 /* no local result, add as new element */
194 if (old == NULL) {
195 if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
196 return -1;
198 talloc_free(discard_const_p(char, old->name));
201 /* copy new element */
202 *old = *el;
204 /* and make sure we reference the contents */
205 if (!talloc_reference(msg->elements, el->name)) {
206 return -1;
208 if (!talloc_reference(msg->elements, el->values)) {
209 return -1;
212 return 0;
215 /* Map a message element back into the local partition. */
216 static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module,
217 void *mem_ctx,
218 const struct ldb_map_attribute *map,
219 const char *attr_name,
220 const struct ldb_message_element *old)
222 struct ldb_message_element *el;
223 unsigned int i;
225 el = talloc_zero(mem_ctx, struct ldb_message_element);
226 if (el == NULL) {
227 map_oom(module);
228 return NULL;
231 el->values = talloc_array(el, struct ldb_val, old->num_values);
232 if (el->values == NULL) {
233 talloc_free(el);
234 map_oom(module);
235 return NULL;
238 el->name = talloc_strdup(el, attr_name);
239 if (el->name == NULL) {
240 talloc_free(el);
241 map_oom(module);
242 return NULL;
245 for (i = 0; i < old->num_values; i++) {
246 el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
247 /* Conversions might fail, in which case bail */
248 if (!el->values[i].data) {
249 talloc_free(el);
250 return NULL;
252 el->num_values++;
255 return el;
258 /* Merge a remote message element into a local message. */
259 static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local,
260 struct ldb_message *remote, const char *attr_name)
262 const struct ldb_map_context *data = map_get_context(module);
263 const struct ldb_map_attribute *map;
264 struct ldb_message_element *old, *el=NULL;
265 const char *remote_name = NULL;
266 struct ldb_context *ldb;
268 ldb = ldb_module_get_ctx(module);
270 /* We handle wildcards in ldb_msg_el_merge_wildcard */
271 if (ldb_attr_cmp(attr_name, "*") == 0) {
272 return LDB_SUCCESS;
275 map = map_attr_find_local(data, attr_name);
277 /* Unknown attribute in remote message:
278 * skip, attribute was probably auto-generated */
279 if (map == NULL) {
280 return LDB_SUCCESS;
283 switch (map->type) {
284 case LDB_MAP_IGNORE:
285 break;
286 case LDB_MAP_CONVERT:
287 remote_name = map->u.convert.remote_name;
288 break;
289 case LDB_MAP_KEEP:
290 remote_name = attr_name;
291 break;
292 case LDB_MAP_RENAME:
293 remote_name = map->u.rename.remote_name;
294 break;
295 case LDB_MAP_GENERATE:
296 break;
299 switch (map->type) {
300 case LDB_MAP_IGNORE:
301 return LDB_SUCCESS;
303 case LDB_MAP_CONVERT:
304 if (map->u.convert.convert_remote == NULL) {
305 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
306 "Skipping attribute '%s': "
307 "'convert_remote' not set",
308 attr_name);
309 return LDB_SUCCESS;
311 /* fall through */
312 case LDB_MAP_KEEP:
313 case LDB_MAP_RENAME:
314 old = ldb_msg_find_element(remote, remote_name);
315 if (old) {
316 el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
317 } else {
318 return LDB_ERR_NO_SUCH_ATTRIBUTE;
320 break;
322 case LDB_MAP_GENERATE:
323 if (map->u.generate.generate_local == NULL) {
324 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
325 "Skipping attribute '%s': "
326 "'generate_local' not set",
327 attr_name);
328 return LDB_SUCCESS;
331 el = map->u.generate.generate_local(module, local, attr_name, remote);
332 if (!el) {
333 /* Generation failure is probably due to lack of source attributes */
334 return LDB_ERR_NO_SUCH_ATTRIBUTE;
336 break;
339 if (el == NULL) {
340 return LDB_ERR_NO_SUCH_ATTRIBUTE;
343 return ldb_msg_replace(local, el);
346 /* Handle wildcard parts of merging a remote message element into a local message. */
347 static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local,
348 struct ldb_message *remote)
350 const struct ldb_map_context *data = map_get_context(module);
351 const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
352 struct ldb_message_element *el=NULL;
353 unsigned int i;
354 int ret;
356 /* Perhaps we have a mapping for "*" */
357 if (map && map->type == LDB_MAP_KEEP) {
358 /* We copy everything over, and hope that anything with a
359 more specific rule is overwritten */
360 for (i = 0; i < remote->num_elements; i++) {
361 el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name,
362 &remote->elements[i]);
363 if (el == NULL) {
364 return LDB_ERR_OPERATIONS_ERROR;
367 ret = ldb_msg_replace(local, el);
368 if (ret) {
369 return ret;
374 /* Now walk the list of possible mappings, and apply each */
375 for (i = 0; data->attribute_maps[i].local_name; i++) {
376 ret = ldb_msg_el_merge(module, local, remote,
377 data->attribute_maps[i].local_name);
378 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
379 continue;
380 } else if (ret) {
381 return ret;
382 } else {
383 continue;
387 return LDB_SUCCESS;
390 /* Mapping messages
391 * ================ */
393 /* Merge two local messages into a single one. */
394 static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2)
396 unsigned int i;
397 int ret;
399 for (i = 0; i < msg2->num_elements; i++) {
400 ret = ldb_msg_replace(msg1, &msg2->elements[i]);
401 if (ret) {
402 return ret;
406 return LDB_SUCCESS;
409 /* Merge a local and a remote message into a single local one. */
410 static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local,
411 struct ldb_message *remote)
413 unsigned int i;
414 int ret;
415 const char * const *attrs = ac->all_attrs;
416 if (!attrs) {
417 ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
418 if (ret) {
419 return ret;
423 for (i = 0; attrs && attrs[i]; i++) {
424 if (ldb_attr_cmp(attrs[i], "*") == 0) {
425 ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
426 if (ret) {
427 return ret;
429 break;
433 /* Try to map each attribute back;
434 * Add to local message is possible,
435 * Overwrite old local attribute if necessary */
436 for (i = 0; attrs && attrs[i]; i++) {
437 ret = ldb_msg_el_merge(ac->module, local, remote,
438 attrs[i]);
439 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
440 } else if (ret) {
441 return ret;
445 return LDB_SUCCESS;
448 /* Mapping search results
449 * ====================== */
451 /* Map a search result back into the local partition. */
452 static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares)
454 struct ldb_message *msg;
455 struct ldb_dn *dn;
456 int ret;
458 /* There is no result message, skip */
459 if (ares->type != LDB_REPLY_ENTRY) {
460 return 0;
463 /* Create a new result message */
464 msg = ldb_msg_new(ares);
465 if (msg == NULL) {
466 map_oom(ac->module);
467 return -1;
470 /* Merge remote message into new message */
471 ret = ldb_msg_merge_remote(ac, msg, ares->message);
472 if (ret) {
473 talloc_free(msg);
474 return ret;
477 /* Create corresponding local DN */
478 dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
479 if (dn == NULL) {
480 talloc_free(msg);
481 return -1;
483 msg->dn = dn;
485 /* Store new message with new DN as the result */
486 talloc_free(ares->message);
487 ares->message = msg;
489 return 0;
492 /* Mapping parse trees
493 * =================== */
495 /* Check whether a parse tree can safely be split in two. */
496 static bool ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree)
498 const struct ldb_parse_tree *subtree = tree;
499 bool negate = false;
501 while (subtree) {
502 switch (subtree->operation) {
503 case LDB_OP_NOT:
504 negate = !negate;
505 subtree = subtree->u.isnot.child;
506 continue;
508 case LDB_OP_AND:
509 return !negate; /* if negate: False */
511 case LDB_OP_OR:
512 return negate; /* if negate: True */
514 default:
515 return true; /* simple parse tree */
519 return true; /* no parse tree */
522 /* Collect a list of attributes required to match a given parse tree. */
523 static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree)
525 const char **new_attrs;
526 unsigned int i;
527 int ret;
529 if (tree == NULL) {
530 return 0;
533 switch (tree->operation) {
534 case LDB_OP_OR:
535 case LDB_OP_AND: /* attributes stored in list of subtrees */
536 for (i = 0; i < tree->u.list.num_elements; i++) {
537 ret = ldb_parse_tree_collect_attrs(module, mem_ctx,
538 attrs, tree->u.list.elements[i]);
539 if (ret) {
540 return ret;
543 return 0;
545 case LDB_OP_NOT: /* attributes stored in single subtree */
546 return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
548 default: /* single attribute in tree */
549 new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr);
550 talloc_free(*attrs);
551 *attrs = new_attrs;
552 return 0;
555 return -1;
558 static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
560 /* Select a negated subtree that queries attributes in the local partition */
561 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)
563 struct ldb_parse_tree *child;
564 int ret;
566 /* Prepare new tree */
567 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
568 if (*new == NULL) {
569 map_oom(module);
570 return -1;
573 /* Generate new subtree */
574 ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
575 if (ret) {
576 talloc_free(*new);
577 return ret;
580 /* Prune tree without subtree */
581 if (child == NULL) {
582 talloc_free(*new);
583 *new = NULL;
584 return 0;
587 (*new)->u.isnot.child = child;
589 return ret;
592 /* Select a list of subtrees that query attributes in the local partition */
593 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)
595 unsigned int i, j;
596 int ret=0;
598 /* Prepare new tree */
599 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
600 if (*new == NULL) {
601 map_oom(module);
602 return -1;
605 /* Prepare list of subtrees */
606 (*new)->u.list.num_elements = 0;
607 (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
608 if ((*new)->u.list.elements == NULL) {
609 map_oom(module);
610 talloc_free(*new);
611 return -1;
614 /* Generate new list of subtrees */
615 j = 0;
616 for (i = 0; i < tree->u.list.num_elements; i++) {
617 struct ldb_parse_tree *child;
618 ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
619 if (ret) {
620 talloc_free(*new);
621 return ret;
624 if (child) {
625 (*new)->u.list.elements[j] = child;
626 j++;
630 /* Prune tree without subtrees */
631 if (j == 0) {
632 talloc_free(*new);
633 *new = NULL;
634 return 0;
637 /* Fix subtree list size */
638 (*new)->u.list.num_elements = j;
639 (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
641 return ret;
644 /* Select a simple subtree that queries attributes in the local partition */
645 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)
647 /* Prepare new tree */
648 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
649 if (*new == NULL) {
650 map_oom(module);
651 return -1;
654 return 0;
657 /* Select subtrees that query attributes in the local partition */
658 static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
660 const struct ldb_map_context *data = map_get_context(module);
662 if (tree == NULL) {
663 return 0;
666 if (tree->operation == LDB_OP_NOT) {
667 return map_subtree_select_local_not(module, mem_ctx, new, tree);
670 if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
671 return map_subtree_select_local_list(module, mem_ctx, new, tree);
674 if (map_attr_check_remote(data, tree->u.equality.attr)) {
675 *new = NULL;
676 return 0;
679 return map_subtree_select_local_simple(module, mem_ctx, new, tree);
682 static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
684 /* Collect a negated subtree that queries attributes in the remote partition */
685 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)
687 struct ldb_parse_tree *child;
688 int ret;
690 /* Prepare new tree */
691 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
692 if (*new == NULL) {
693 map_oom(module);
694 return -1;
697 /* Generate new subtree */
698 ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
699 if (ret) {
700 talloc_free(*new);
701 return ret;
704 /* Prune tree without subtree */
705 if (child == NULL) {
706 talloc_free(*new);
707 *new = NULL;
708 return 0;
711 (*new)->u.isnot.child = child;
713 return ret;
716 /* Collect a list of subtrees that query attributes in the remote partition */
717 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)
719 unsigned int i, j;
720 int ret=0;
722 /* Prepare new tree */
723 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
724 if (*new == NULL) {
725 map_oom(module);
726 return -1;
729 /* Prepare list of subtrees */
730 (*new)->u.list.num_elements = 0;
731 (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
732 if ((*new)->u.list.elements == NULL) {
733 map_oom(module);
734 talloc_free(*new);
735 return -1;
738 /* Generate new list of subtrees */
739 j = 0;
740 for (i = 0; i < tree->u.list.num_elements; i++) {
741 struct ldb_parse_tree *child;
742 ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
743 if (ret) {
744 talloc_free(*new);
745 return ret;
748 if (child) {
749 (*new)->u.list.elements[j] = child;
750 j++;
754 /* Prune tree without subtrees */
755 if (j == 0) {
756 talloc_free(*new);
757 *new = NULL;
758 return 0;
761 /* Fix subtree list size */
762 (*new)->u.list.num_elements = j;
763 (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
765 return ret;
768 /* Collect a simple subtree that queries attributes in the remote partition */
769 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)
771 const char *attr;
773 /* Prepare new tree */
774 *new = talloc(mem_ctx, struct ldb_parse_tree);
775 if (*new == NULL) {
776 map_oom(module);
777 return -1;
779 **new = *tree;
781 if (map->type == LDB_MAP_KEEP) {
782 /* Nothing to do here */
783 return 0;
786 /* Store attribute and value in new tree */
787 switch (tree->operation) {
788 case LDB_OP_PRESENT:
789 attr = map_attr_map_local(*new, map, tree->u.present.attr);
790 (*new)->u.present.attr = attr;
791 break;
792 case LDB_OP_SUBSTRING:
794 attr = map_attr_map_local(*new, map, tree->u.substring.attr);
795 (*new)->u.substring.attr = attr;
796 break;
798 case LDB_OP_EQUALITY:
799 attr = map_attr_map_local(*new, map, tree->u.equality.attr);
800 (*new)->u.equality.attr = attr;
801 break;
802 case LDB_OP_LESS:
803 case LDB_OP_GREATER:
804 case LDB_OP_APPROX:
805 attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
806 (*new)->u.comparison.attr = attr;
807 break;
808 case LDB_OP_EXTENDED:
809 attr = map_attr_map_local(*new, map, tree->u.extended.attr);
810 (*new)->u.extended.attr = attr;
811 break;
812 default: /* unknown kind of simple subtree */
813 talloc_free(*new);
814 return -1;
817 if (attr == NULL) {
818 talloc_free(*new);
819 *new = NULL;
820 return 0;
823 if (map->type == LDB_MAP_RENAME) {
824 /* Nothing more to do here, the attribute has been renamed */
825 return 0;
828 /* Store attribute and value in new tree */
829 switch (tree->operation) {
830 case LDB_OP_PRESENT:
831 break;
832 case LDB_OP_SUBSTRING:
834 int i;
835 /* Map value */
836 (*new)->u.substring.chunks = NULL;
837 for (i=0; tree->u.substring.chunks[i]; i++) {
838 (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2);
839 if (!(*new)->u.substring.chunks) {
840 talloc_free(*new);
841 *new = NULL;
842 return 0;
844 (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
845 if (!(*new)->u.substring.chunks[i]) {
846 talloc_free(*new);
847 *new = NULL;
848 return 0;
850 *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]);
851 (*new)->u.substring.chunks[i+1] = NULL;
853 break;
855 case LDB_OP_EQUALITY:
856 (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
857 break;
858 case LDB_OP_LESS:
859 case LDB_OP_GREATER:
860 case LDB_OP_APPROX:
861 (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
862 break;
863 case LDB_OP_EXTENDED:
864 (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value);
865 (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id);
866 break;
867 default: /* unknown kind of simple subtree */
868 talloc_free(*new);
869 return -1;
872 return 0;
875 /* Collect subtrees that query attributes in the remote partition */
876 static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
878 const struct ldb_map_context *data = map_get_context(module);
879 const struct ldb_map_attribute *map;
880 struct ldb_context *ldb;
882 ldb = ldb_module_get_ctx(module);
884 if (tree == NULL) {
885 return 0;
888 if (tree->operation == LDB_OP_NOT) {
889 return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
892 if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
893 return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
896 if (!map_attr_check_remote(data, tree->u.equality.attr)) {
897 *new = NULL;
898 return 0;
901 map = map_attr_find_local(data, tree->u.equality.attr);
902 if (map->convert_operator) {
903 return map->convert_operator(module, mem_ctx, new, tree);
906 if (map->type == LDB_MAP_GENERATE) {
907 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
908 "Skipping attribute '%s': "
909 "'convert_operator' not set",
910 tree->u.equality.attr);
911 *new = NULL;
912 return 0;
915 return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map);
918 /* Split subtrees that query attributes in the local partition from
919 * those that query the remote partition. */
920 static int ldb_parse_tree_partition(struct ldb_module *module,
921 void *mem_ctx,
922 struct ldb_parse_tree **local_tree,
923 struct ldb_parse_tree **remote_tree,
924 const struct ldb_parse_tree *tree)
926 int ret;
928 *local_tree = NULL;
929 *remote_tree = NULL;
931 /* No original tree */
932 if (tree == NULL) {
933 return 0;
936 /* Generate local tree */
937 ret = map_subtree_select_local(module, mem_ctx, local_tree, tree);
938 if (ret) {
939 return ret;
942 /* Generate remote tree */
943 ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree);
944 if (ret) {
945 talloc_free(*local_tree);
946 return ret;
949 return 0;
952 /* Collect a list of attributes required either explicitly from a
953 * given list or implicitly from a given parse tree; split the
954 * collected list into local and remote parts. */
955 static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac,
956 const char * const *search_attrs,
957 const struct ldb_parse_tree *tree)
959 void *tmp_ctx;
960 const char **tree_attrs;
961 const char **remote_attrs;
962 const char **local_attrs;
963 int ret;
965 /* There is no tree, just partition the searched attributes */
966 if (tree == NULL) {
967 ret = map_attrs_partition(module, ac,
968 &local_attrs, &remote_attrs, search_attrs);
969 if (ret == 0) {
970 ac->local_attrs = local_attrs;
971 ac->remote_attrs = remote_attrs;
972 ac->all_attrs = search_attrs;
974 return ret;
977 /* Create context for temporary memory */
978 tmp_ctx = talloc_new(ac);
979 if (tmp_ctx == NULL) {
980 goto oom;
983 /* Prepare list of attributes from tree */
984 tree_attrs = talloc_array(tmp_ctx, const char *, 1);
985 if (tree_attrs == NULL) {
986 talloc_free(tmp_ctx);
987 goto oom;
989 tree_attrs[0] = NULL;
991 /* Collect attributes from tree */
992 ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
993 if (ret) {
994 goto done;
997 /* Merge attributes from search operation */
998 ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
999 if (ret) {
1000 goto done;
1003 /* Split local from remote attributes */
1004 ret = map_attrs_partition(module, ac, &local_attrs,
1005 &remote_attrs, tree_attrs);
1007 if (ret == 0) {
1008 ac->local_attrs = local_attrs;
1009 ac->remote_attrs = remote_attrs;
1010 talloc_steal(ac, tree_attrs);
1011 ac->all_attrs = tree_attrs;
1013 done:
1014 /* Free temporary memory */
1015 talloc_free(tmp_ctx);
1016 return ret;
1018 oom:
1019 map_oom(module);
1020 return -1;
1024 /* Outbound requests: search
1025 * ========================= */
1027 static int map_remote_search_callback(struct ldb_request *req,
1028 struct ldb_reply *ares);
1029 static int map_local_merge_callback(struct ldb_request *req,
1030 struct ldb_reply *ares);
1031 static int map_search_local(struct map_context *ac);
1033 static int map_save_entry(struct map_context *ac, struct ldb_reply *ares)
1035 struct map_reply *mr;
1037 mr = talloc_zero(ac, struct map_reply);
1038 if (mr == NULL) {
1039 map_oom(ac->module);
1040 return LDB_ERR_OPERATIONS_ERROR;
1042 mr->remote = talloc_steal(mr, ares);
1043 if (ac->r_current) {
1044 ac->r_current->next = mr;
1045 } else {
1046 /* first entry */
1047 ac->r_list = mr;
1049 ac->r_current = mr;
1051 return LDB_SUCCESS;
1054 /* Pass a merged search result up the callback chain. */
1055 int map_return_entry(struct map_context *ac, struct ldb_reply *ares)
1057 struct ldb_message_element *el;
1058 const char * const *attrs;
1059 struct ldb_context *ldb;
1060 unsigned int i;
1062 ldb = ldb_module_get_ctx(ac->module);
1064 /* Merged result doesn't match original query, skip */
1065 if (!ldb_match_msg(ldb, ares->message,
1066 ac->req->op.search.tree,
1067 ac->req->op.search.base,
1068 ac->req->op.search.scope)) {
1069 ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
1070 "Skipping record '%s': "
1071 "doesn't match original search",
1072 ldb_dn_get_linearized(ares->message->dn));
1073 return LDB_SUCCESS;
1076 /* Limit result to requested attrs */
1077 if (ac->req->op.search.attrs &&
1078 (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) {
1080 attrs = ac->req->op.search.attrs;
1081 i = 0;
1083 while (i < ares->message->num_elements) {
1085 el = &ares->message->elements[i];
1086 if ( ! ldb_attr_in_list(attrs, el->name)) {
1087 ldb_msg_remove_element(ares->message, el);
1088 } else {
1089 i++;
1094 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1097 /* Search a record. */
1098 int map_search(struct ldb_module *module, struct ldb_request *req)
1100 struct ldb_parse_tree *remote_tree;
1101 struct ldb_parse_tree *local_tree;
1102 struct ldb_request *remote_req;
1103 struct ldb_context *ldb;
1104 struct map_context *ac;
1105 int ret;
1107 const char *wildcard[] = { "*", NULL };
1108 const char * const *attrs;
1110 ldb = ldb_module_get_ctx(module);
1112 /* if we're not yet initialized, go to the next module */
1113 if (!ldb_module_get_private(module))
1114 return ldb_next_request(module, req);
1116 /* Do not manipulate our control entries */
1117 if (ldb_dn_is_special(req->op.search.base)) {
1118 return ldb_next_request(module, req);
1121 /* No mapping requested, skip to next module */
1122 if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
1123 return ldb_next_request(module, req);
1126 /* TODO: How can we be sure about which partition we are
1127 * targetting when there is no search base? */
1129 /* Prepare context and handle */
1130 ac = map_init_context(module, req);
1131 if (ac == NULL) {
1132 return LDB_ERR_OPERATIONS_ERROR;
1135 /* It is easier to deal with the two different ways of
1136 * expressing the wildcard in the same codepath */
1137 attrs = req->op.search.attrs;
1138 if (attrs == NULL) {
1139 attrs = wildcard;
1142 /* Split local from remote attrs */
1143 ret = map_attrs_collect_and_partition(module, ac,
1144 attrs, req->op.search.tree);
1145 if (ret) {
1146 return LDB_ERR_OPERATIONS_ERROR;
1149 /* Split local from remote tree */
1150 ret = ldb_parse_tree_partition(module, ac,
1151 &local_tree, &remote_tree,
1152 req->op.search.tree);
1153 if (ret) {
1154 return LDB_ERR_OPERATIONS_ERROR;
1157 if (((local_tree != NULL) && (remote_tree != NULL)) &&
1158 (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
1159 /* The query can't safely be split, enumerate the remote partition */
1160 local_tree = NULL;
1161 remote_tree = NULL;
1164 if (local_tree == NULL) {
1165 /* Construct default local parse tree */
1166 local_tree = talloc_zero(ac, struct ldb_parse_tree);
1167 if (local_tree == NULL) {
1168 map_oom(ac->module);
1169 return LDB_ERR_OPERATIONS_ERROR;
1172 local_tree->operation = LDB_OP_PRESENT;
1173 local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
1175 if (remote_tree == NULL) {
1176 /* Construct default remote parse tree */
1177 remote_tree = ldb_parse_tree(ac, NULL);
1178 if (remote_tree == NULL) {
1179 return LDB_ERR_OPERATIONS_ERROR;
1183 ac->local_tree = local_tree;
1185 /* Prepare the remote operation */
1186 ret = ldb_build_search_req_ex(&remote_req, ldb, ac,
1187 req->op.search.base,
1188 req->op.search.scope,
1189 remote_tree,
1190 ac->remote_attrs,
1191 req->controls,
1192 ac, map_remote_search_callback,
1193 req);
1194 if (ret != LDB_SUCCESS) {
1195 return LDB_ERR_OPERATIONS_ERROR;
1198 return ldb_next_remote_request(module, remote_req);
1201 /* Now, search the local part of a remote search result. */
1202 static int map_remote_search_callback(struct ldb_request *req,
1203 struct ldb_reply *ares)
1205 struct map_context *ac;
1206 int ret;
1208 ac = talloc_get_type(req->context, struct map_context);
1210 if (!ares) {
1211 return ldb_module_done(ac->req, NULL, NULL,
1212 LDB_ERR_OPERATIONS_ERROR);
1214 if (ares->error != LDB_SUCCESS) {
1215 return ldb_module_done(ac->req, ares->controls,
1216 ares->response, ares->error);
1219 switch (ares->type) {
1220 case LDB_REPLY_REFERRAL:
1222 /* ignore referrals */
1223 talloc_free(ares);
1224 return LDB_SUCCESS;
1226 case LDB_REPLY_ENTRY:
1228 /* Map result record into a local message */
1229 ret = map_reply_remote(ac, ares);
1230 if (ret) {
1231 talloc_free(ares);
1232 return ldb_module_done(ac->req, NULL, NULL,
1233 LDB_ERR_OPERATIONS_ERROR);
1236 /* if we have no local db, then we can just return the reply to
1237 * the upper layer, otherwise we must save it and process it
1238 * when all replies ahve been gathered */
1239 if ( ! map_check_local_db(ac->module)) {
1240 ret = map_return_entry(ac, ares);
1241 } else {
1242 ret = map_save_entry(ac,ares);
1245 if (ret != LDB_SUCCESS) {
1246 talloc_free(ares);
1247 return ldb_module_done(ac->req, NULL, NULL,
1248 LDB_ERR_OPERATIONS_ERROR);
1250 break;
1252 case LDB_REPLY_DONE:
1254 if ( ! map_check_local_db(ac->module)) {
1255 return ldb_module_done(ac->req, ares->controls,
1256 ares->response, LDB_SUCCESS);
1259 /* reset the pointer to the start of the list */
1260 ac->r_current = ac->r_list;
1262 /* no entry just return */
1263 if (ac->r_current == NULL) {
1264 ret = ldb_module_done(ac->req, ares->controls,
1265 ares->response, LDB_SUCCESS);
1266 talloc_free(ares);
1267 return ret;
1270 ac->remote_done_ares = talloc_steal(ac, ares);
1272 ret = map_search_local(ac);
1273 if (ret != LDB_SUCCESS) {
1274 return ldb_module_done(ac->req, NULL, NULL, ret);
1278 return LDB_SUCCESS;
1281 static int map_search_local(struct map_context *ac)
1283 struct ldb_request *search_req;
1285 if (ac->r_current == NULL || ac->r_current->remote == NULL) {
1286 return LDB_ERR_OPERATIONS_ERROR;
1289 /* Prepare local search request */
1290 /* TODO: use GUIDs here instead? */
1291 search_req = map_search_base_req(ac,
1292 ac->r_current->remote->message->dn,
1293 NULL, NULL,
1294 ac, map_local_merge_callback);
1295 if (search_req == NULL) {
1296 return LDB_ERR_OPERATIONS_ERROR;
1299 return ldb_next_request(ac->module, search_req);
1302 /* Merge the remote and local parts of a search result. */
1303 int map_local_merge_callback(struct ldb_request *req, struct ldb_reply *ares)
1305 struct ldb_context *ldb;
1306 struct map_context *ac;
1307 int ret;
1309 ac = talloc_get_type(req->context, struct map_context);
1310 ldb = ldb_module_get_ctx(ac->module);
1312 if (!ares) {
1313 return ldb_module_done(ac->req, NULL, NULL,
1314 LDB_ERR_OPERATIONS_ERROR);
1316 if (ares->error != LDB_SUCCESS) {
1317 return ldb_module_done(ac->req, ares->controls,
1318 ares->response, ares->error);
1321 switch (ares->type) {
1322 case LDB_REPLY_ENTRY:
1323 /* We have already found a local record */
1324 if (ac->r_current->local) {
1325 talloc_free(ares);
1326 ldb_set_errstring(ldb, "ldb_map: Too many results!");
1327 return ldb_module_done(ac->req, NULL, NULL,
1328 LDB_ERR_OPERATIONS_ERROR);
1331 /* Store local result */
1332 ac->r_current->local = talloc_steal(ac->r_current, ares);
1334 break;
1336 case LDB_REPLY_REFERRAL:
1337 /* ignore referrals */
1338 talloc_free(ares);
1339 break;
1341 case LDB_REPLY_DONE:
1342 /* We don't need the local 'ares', but we will use the remote one from below */
1343 talloc_free(ares);
1345 /* No local record found, map and send remote record */
1346 if (ac->r_current->local != NULL) {
1347 /* Merge remote into local message */
1348 ret = ldb_msg_merge_local(ac->module,
1349 ac->r_current->local->message,
1350 ac->r_current->remote->message);
1351 if (ret == LDB_SUCCESS) {
1352 ret = map_return_entry(ac, ac->r_current->local);
1354 if (ret != LDB_SUCCESS) {
1355 return ldb_module_done(ac->req, NULL, NULL,
1356 LDB_ERR_OPERATIONS_ERROR);
1358 } else {
1359 ret = map_return_entry(ac, ac->r_current->remote);
1360 if (ret != LDB_SUCCESS) {
1361 return ldb_module_done(ac->req,
1362 NULL, NULL, ret);
1366 if (ac->r_current->next != NULL) {
1367 ac->r_current = ac->r_current->next;
1368 if (ac->r_current->remote->type == LDB_REPLY_ENTRY) {
1369 ret = map_search_local(ac);
1370 if (ret != LDB_SUCCESS) {
1371 return ldb_module_done(ac->req,
1372 NULL, NULL, ret);
1374 break;
1378 /* ok we are done with all search, finally it is time to
1379 * finish operations for this module */
1380 return ldb_module_done(ac->req,
1381 ac->remote_done_ares->controls,
1382 ac->remote_done_ares->response,
1383 ac->remote_done_ares->error);
1386 return LDB_SUCCESS;