r25068: Older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for every opcode on the
[Samba.git] / source / lib / ldb / modules / ldb_map_outbound.c
blob6305e6666fe0915b770edd3af4f99444b858b64a
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
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
10 * later license.
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.
27 #include "includes.h"
28 #include "ldb/include/includes.h"
30 #include "ldb/modules/ldb_map.h"
31 #include "ldb/modules/ldb_map_private.h"
34 /* Mapping attributes
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);
41 const char **result;
42 int i, last;
44 if (attrs == NULL)
45 return NULL;
47 last = 0;
48 result = talloc_array(mem_ctx, const char *, 1);
49 if (result == NULL) {
50 goto failed;
52 result[0] = NULL;
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);
59 if (result == NULL) {
60 goto failed;
63 result[last] = talloc_strdup(result, attrs[i]);
64 result[last+1] = NULL;
65 last++;
69 return result;
71 failed:
72 talloc_free(result);
73 map_oom(module);
74 return 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);
82 const char **result;
83 const struct ldb_map_attribute *map;
84 const char *name=NULL;
85 int i, j, last;
86 int ret;
88 last = 0;
89 result = talloc_array(mem_ctx, const char *, 1);
90 if (result == NULL) {
91 goto failed;
93 result[0] = NULL;
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) {
101 goto failed;
103 ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
104 if (ret != LDB_SUCCESS) {
105 goto failed;
108 attrs = new_attrs;
109 break;
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 */
117 name = attrs[i];
118 goto named;
121 /* Add remote names of mapped attrs */
122 map = map_attr_find_local(data, attrs[i]);
123 if (map == NULL) {
124 continue;
127 switch (map->type) {
128 case MAP_IGNORE:
129 continue;
131 case MAP_KEEP:
132 name = attrs[i];
133 goto named;
135 case MAP_RENAME:
136 case MAP_CONVERT:
137 name = map->u.rename.remote_name;
138 goto named;
140 case MAP_GENERATE:
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) {
145 goto failed;
148 result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
149 result[last+1] = NULL;
150 last++;
152 continue;
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) {
158 goto failed;
161 result[last] = talloc_strdup(result, name);
162 result[last+1] = NULL;
163 last++;
166 return result;
168 failed:
169 talloc_free(result);
170 map_oom(module);
171 return 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);
181 return 0;
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 */
195 if (old == NULL) {
196 if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
197 return -1;
199 talloc_free(old->name);
202 /* copy new element */
203 *old = *el;
205 /* and make sure we reference the contents */
206 if (!talloc_reference(msg->elements, el->name)) {
207 return -1;
209 if (!talloc_reference(msg->elements, el->values)) {
210 return -1;
213 return 0;
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,
218 void *mem_ctx,
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;
224 int i;
226 el = talloc_zero(mem_ctx, struct ldb_message_element);
227 if (el == NULL) {
228 map_oom(module);
229 return NULL;
232 el->num_values = old->num_values;
233 el->values = talloc_array(el, struct ldb_val, el->num_values);
234 if (el->values == NULL) {
235 talloc_free(el);
236 map_oom(module);
237 return NULL;
240 el->name = talloc_strdup(el, attr_name);
241 if (el->name == NULL) {
242 talloc_free(el);
243 map_oom(module);
244 return 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]);
251 return el;
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) {
265 return 0;
268 map = map_attr_find_local(data, attr_name);
270 /* Unknown attribute in remote message:
271 * skip, attribute was probably auto-generated */
272 if (map == NULL) {
273 return 0;
276 switch (map->type) {
277 case MAP_IGNORE:
278 break;
279 case MAP_CONVERT:
280 remote_name = map->u.convert.remote_name;
281 break;
282 case MAP_KEEP:
283 remote_name = attr_name;
284 break;
285 case MAP_RENAME:
286 remote_name = map->u.rename.remote_name;
287 break;
288 case MAP_GENERATE:
289 break;
292 switch (map->type) {
293 case MAP_IGNORE:
294 return 0;
296 case MAP_CONVERT:
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",
301 attr_name);
302 return 0;
304 /* fall through */
305 case MAP_KEEP:
306 case MAP_RENAME:
307 old = ldb_msg_find_element(remote, remote_name);
308 if (old) {
309 el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
310 } else {
311 return LDB_ERR_NO_SUCH_ATTRIBUTE;
313 break;
315 case MAP_GENERATE:
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",
320 attr_name);
321 return 0;
324 el = map->u.generate.generate_local(module, local, attr_name, remote);
325 if (!el) {
326 /* Generation failure is probably due to lack of source attributes */
327 return LDB_ERR_NO_SUCH_ATTRIBUTE;
329 break;
332 if (el == NULL) {
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;
346 int i, ret;
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]);
355 if (el == NULL) {
356 return LDB_ERR_OPERATIONS_ERROR;
359 ret = ldb_msg_replace(local, el);
360 if (ret) {
361 return ret;
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) {
371 continue;
372 } else if (ret) {
373 return ret;
374 } else {
375 continue;
379 return 0;
382 /* Mapping messages
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)
388 int i, ret;
390 for (i = 0; i < msg2->num_elements; i++) {
391 ret = ldb_msg_replace(msg1, &msg2->elements[i]);
392 if (ret) {
393 return ret;
397 return 0;
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)
404 int i, ret;
405 const char * const *attrs = ac->all_attrs;
406 if (!attrs) {
407 ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
408 if (ret) {
409 return ret;
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);
416 if (ret) {
417 return ret;
419 break;
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,
428 attrs[i]);
429 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
430 } else if (ret) {
431 return ret;
435 return 0;
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;
445 struct ldb_dn *dn;
446 int ret;
448 /* There is no result message, skip */
449 if (ares->type != LDB_REPLY_ENTRY) {
450 return 0;
453 /* Create a new result message */
454 msg = ldb_msg_new(ares);
455 if (msg == NULL) {
456 map_oom(ac->module);
457 return -1;
460 /* Merge remote message into new message */
461 ret = ldb_msg_merge_remote(ac, msg, ares->message);
462 if (ret) {
463 talloc_free(msg);
464 return ret;
467 /* Create corresponding local DN */
468 dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
469 if (dn == NULL) {
470 talloc_free(msg);
471 return -1;
473 msg->dn = dn;
475 /* Store new message with new DN as the result */
476 talloc_free(ares->message);
477 ares->message = msg;
479 return 0;
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;
489 BOOL negate = False;
491 while (subtree) {
492 switch (subtree->operation) {
493 case LDB_OP_NOT:
494 negate = !negate;
495 subtree = subtree->u.isnot.child;
496 continue;
498 case LDB_OP_AND:
499 return !negate; /* if negate: False */
501 case LDB_OP_OR:
502 return negate; /* if negate: True */
504 default:
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;
516 int i, ret;
518 if (tree == NULL) {
519 return 0;
522 switch (tree->operation) {
523 case LDB_OP_OR:
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]);
528 if (ret) {
529 return ret;
532 return 0;
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);
539 talloc_free(*attrs);
540 *attrs = new_attrs;
541 return 0;
544 return -1;
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;
553 int ret;
555 /* Prepare new tree */
556 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
557 if (*new == NULL) {
558 map_oom(module);
559 return -1;
562 /* Generate new subtree */
563 ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
564 if (ret) {
565 talloc_free(*new);
566 return ret;
569 /* Prune tree without subtree */
570 if (child == NULL) {
571 talloc_free(*new);
572 *new = NULL;
573 return 0;
576 (*new)->u.isnot.child = child;
578 return ret;
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)
584 int i, j, ret=0;
586 /* Prepare new tree */
587 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
588 if (*new == NULL) {
589 map_oom(module);
590 return -1;
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) {
597 map_oom(module);
598 talloc_free(*new);
599 return -1;
602 /* Generate new list of subtrees */
603 j = 0;
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]);
607 if (ret) {
608 talloc_free(*new);
609 return ret;
612 if (child) {
613 (*new)->u.list.elements[j] = child;
614 j++;
618 /* Prune tree without subtrees */
619 if (j == 0) {
620 talloc_free(*new);
621 *new = NULL;
622 return 0;
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);
629 return ret;
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));
637 if (*new == NULL) {
638 map_oom(module);
639 return -1;
642 return 0;
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);
650 if (tree == NULL) {
651 return 0;
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)) {
663 *new = NULL;
664 return 0;
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;
676 int ret;
678 /* Prepare new tree */
679 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
680 if (*new == NULL) {
681 map_oom(module);
682 return -1;
685 /* Generate new subtree */
686 ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
687 if (ret) {
688 talloc_free(*new);
689 return ret;
692 /* Prune tree without subtree */
693 if (child == NULL) {
694 talloc_free(*new);
695 *new = NULL;
696 return 0;
699 (*new)->u.isnot.child = child;
701 return ret;
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)
707 int i, j, ret=0;
709 /* Prepare new tree */
710 *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
711 if (*new == NULL) {
712 map_oom(module);
713 return -1;
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) {
720 map_oom(module);
721 talloc_free(*new);
722 return -1;
725 /* Generate new list of subtrees */
726 j = 0;
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]);
730 if (ret) {
731 talloc_free(*new);
732 return ret;
735 if (child) {
736 (*new)->u.list.elements[j] = child;
737 j++;
741 /* Prune tree without subtrees */
742 if (j == 0) {
743 talloc_free(*new);
744 *new = NULL;
745 return 0;
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);
752 return ret;
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)
758 const char *attr;
760 /* Prepare new tree */
761 *new = talloc(mem_ctx, struct ldb_parse_tree);
762 if (*new == NULL) {
763 map_oom(module);
764 return -1;
766 **new = *tree;
768 if (map->type == MAP_KEEP) {
769 /* Nothing to do here */
770 return 0;
773 /* Store attribute and value in new tree */
774 switch (tree->operation) {
775 case LDB_OP_PRESENT:
776 attr = map_attr_map_local(*new, map, tree->u.present.attr);
777 (*new)->u.present.attr = attr;
778 break;
779 case LDB_OP_SUBSTRING:
781 attr = map_attr_map_local(*new, map, tree->u.substring.attr);
782 (*new)->u.substring.attr = attr;
783 break;
785 case LDB_OP_EQUALITY:
786 attr = map_attr_map_local(*new, map, tree->u.equality.attr);
787 (*new)->u.equality.attr = attr;
788 break;
789 case LDB_OP_LESS:
790 case LDB_OP_GREATER:
791 case LDB_OP_APPROX:
792 attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
793 (*new)->u.comparison.attr = attr;
794 break;
795 case LDB_OP_EXTENDED:
796 attr = map_attr_map_local(*new, map, tree->u.extended.attr);
797 (*new)->u.extended.attr = attr;
798 break;
799 default: /* unknown kind of simple subtree */
800 talloc_free(*new);
801 return -1;
804 if (attr == NULL) {
805 talloc_free(*new);
806 *new = NULL;
807 return 0;
810 if (map->type == MAP_RENAME) {
811 /* Nothing more to do here, the attribute has been renamed */
812 return 0;
815 /* Store attribute and value in new tree */
816 switch (tree->operation) {
817 case LDB_OP_PRESENT:
818 break;
819 case LDB_OP_SUBSTRING:
821 int i;
822 /* Map value */
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) {
827 talloc_free(*new);
828 *new = NULL;
829 return 0;
831 (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
832 if (!(*new)->u.substring.chunks[i]) {
833 talloc_free(*new);
834 *new = NULL;
835 return 0;
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;
840 break;
842 case LDB_OP_EQUALITY:
843 (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
844 break;
845 case LDB_OP_LESS:
846 case LDB_OP_GREATER:
847 case LDB_OP_APPROX:
848 (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
849 break;
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);
853 break;
854 default: /* unknown kind of simple subtree */
855 talloc_free(*new);
856 return -1;
859 return 0;
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;
868 if (tree == NULL) {
869 return 0;
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)) {
881 *new = NULL;
882 return 0;
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);
895 *new = NULL;
896 return 0;
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)
906 int ret;
908 *local_tree = NULL;
909 *remote_tree = NULL;
911 /* No original tree */
912 if (tree == NULL) {
913 return 0;
916 /* Generate local tree */
917 ret = map_subtree_select_local(module, local_ctx, local_tree, tree);
918 if (ret) {
919 return ret;
922 /* Generate remote tree */
923 ret = map_subtree_collect_remote(module, remote_ctx, remote_tree, tree);
924 if (ret) {
925 talloc_free(*local_tree);
926 return ret;
929 return 0;
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)
939 void *tmp_ctx;
940 const char **tree_attrs;
941 const char **remote_attrs;
942 const char **local_attrs;
943 int ret;
945 /* Clear initial lists of partitioned attributes */
947 /* Clear initial lists of partitioned attributes */
949 /* There is no tree, just partition the searched attributes */
950 if (tree == NULL) {
951 ret = map_attrs_partition(module, ac,
952 &local_attrs, &remote_attrs, search_attrs);
953 if (ret == 0) {
954 ac->local_attrs = local_attrs;
955 ac->remote_attrs = remote_attrs;
956 ac->all_attrs = search_attrs;
958 return ret;
961 /* Create context for temporary memory */
962 tmp_ctx = talloc_new(ac);
963 if (tmp_ctx == NULL) {
964 goto oom;
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);
971 goto oom;
973 tree_attrs[0] = NULL;
975 /* Collect attributes from tree */
976 ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
977 if (ret) {
978 goto done;
981 /* Merge attributes from search operation */
982 ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
983 if (ret) {
984 goto done;
987 /* Split local from remote attributes */
988 ret = map_attrs_partition(module, ac, &local_attrs,
989 &remote_attrs, tree_attrs);
991 if (ret == 0) {
992 ac->local_attrs = local_attrs;
993 ac->remote_attrs = remote_attrs;
994 talloc_steal(ac, tree_attrs);
995 ac->all_attrs = tree_attrs;
997 done:
998 /* Free temporary memory */
999 talloc_free(tmp_ctx);
1000 return ret;
1002 oom:
1003 map_oom(module);
1004 return -1;
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)
1014 int i;
1016 /* No callback registered, stop */
1017 if (req->callback == NULL) {
1018 return LDB_SUCCESS;
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));
1032 return LDB_SUCCESS;
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);
1041 } else {
1042 i++;
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;
1054 int ret;
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"));
1070 talloc_free(ares);
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);
1079 if (ret) {
1080 talloc_free(ares);
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);
1091 return LDB_SUCCESS;
1093 default:
1094 ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
1095 "Unexpected result type in base search for local entry"));
1096 talloc_free(ares);
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;
1107 int ret;
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);
1124 if (ret) {
1125 talloc_free(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);
1136 if (sc == NULL) {
1137 talloc_free(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) {
1146 talloc_free(ares);
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);
1153 if (req == NULL) {
1154 talloc_free(sc);
1155 talloc_free(ares);
1156 return LDB_ERR_OPERATIONS_ERROR;
1158 ac->num_searches++;
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;
1170 int ret;
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);
1189 if (h == NULL) {
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) {
1196 talloc_free(h);
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) {
1205 goto oom;
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) {
1219 attrs = wildcard;
1222 /* Split local from remote attrs */
1223 ret = map_attrs_collect_and_partition(module, ac,
1224 attrs, req->op.search.tree);
1225 if (ret) {
1226 goto failed;
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);
1235 if (ret) {
1236 goto failed;
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 */
1242 local_tree = NULL;
1243 remote_tree = NULL;
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);
1251 goto failed;
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) {
1261 goto failed;
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) {
1277 req->handle = h;
1279 return ret;
1281 oom:
1282 map_oom(module);
1283 failed:
1284 talloc_free(h);
1285 return LDB_ERR_OPERATIONS_ERROR;