• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/lib/ldb/modules/
1/*
2   ldb database mapping module
3
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
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.
11
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 3 of the License, or
15   (at your option) any later version.
16
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.
21
22   You should have received a copy of the GNU General Public License
23   along with this program.  If not, see <http://www.gnu.org/licenses/>.
24*/
25
26#include "includes.h"
27#include "ldb/include/includes.h"
28
29#include "ldb/modules/ldb_map.h"
30#include "ldb/modules/ldb_map_private.h"
31
32
33/* Mapping attributes
34 * ================== */
35
36/* Select attributes that stay in the local partition. */
37static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
38{
39	const struct ldb_map_context *data = map_get_context(module);
40	const char **result;
41	int i, last;
42
43	if (attrs == NULL)
44		return NULL;
45
46	last = 0;
47	result = talloc_array(mem_ctx, const char *, 1);
48	if (result == NULL) {
49		goto failed;
50	}
51	result[0] = NULL;
52
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;
60			}
61
62			result[last] = talloc_strdup(result, attrs[i]);
63			result[last+1] = NULL;
64			last++;
65		}
66	}
67
68	return result;
69
70failed:
71	talloc_free(result);
72	map_oom(module);
73	return NULL;
74}
75
76/* Collect attributes that are mapped into the remote partition. */
77static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx,
78					     const char * const *attrs)
79{
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	int i, j, last;
85	int ret;
86
87	last = 0;
88	result = talloc_array(mem_ctx, const char *, 1);
89	if (result == NULL) {
90		goto failed;
91	}
92	result[0] = NULL;
93
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;
101			}
102			ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
103			if (ret != LDB_SUCCESS) {
104				goto failed;
105			}
106
107			attrs = new_attrs;
108			break;
109		}
110	}
111
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;
118		}
119
120		/* Add remote names of mapped attrs */
121		map = map_attr_find_local(data, attrs[i]);
122		if (map == NULL) {
123			continue;
124		}
125
126		switch (map->type) {
127		case MAP_IGNORE:
128			continue;
129
130		case MAP_KEEP:
131			name = attrs[i];
132			goto named;
133
134		case MAP_RENAME:
135		case MAP_CONVERT:
136			name = map->u.rename.remote_name;
137			goto named;
138
139		case 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;
145				}
146
147				result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
148				result[last+1] = NULL;
149				last++;
150			}
151			continue;
152		}
153
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;
158		}
159
160		result[last] = talloc_strdup(result, name);
161		result[last+1] = NULL;
162		last++;
163	}
164
165	return result;
166
167failed:
168	talloc_free(result);
169	map_oom(module);
170	return NULL;
171}
172
173/* Split attributes that stay in the local partition from those that
174 * are mapped into the remote partition. */
175static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs)
176{
177	*local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
178	*remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs);
179
180	return 0;
181}
182
183/* Mapping message elements
184 * ======================== */
185
186/* Add an element to a message, overwriting any old identically named elements. */
187static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
188{
189	struct ldb_message_element *old;
190
191	old = ldb_msg_find_element(msg, el->name);
192
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;
197		}
198		talloc_free(old->name);
199	}
200
201	/* copy new element */
202	*old = *el;
203
204	/* and make sure we reference the contents */
205	if (!talloc_reference(msg->elements, el->name)) {
206		return -1;
207	}
208	if (!talloc_reference(msg->elements, el->values)) {
209		return -1;
210	}
211
212	return 0;
213}
214
215/* Map a message element back into the local partition. */
216static 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)
221{
222	struct ldb_message_element *el;
223	int i;
224
225	el = talloc_zero(mem_ctx, struct ldb_message_element);
226	if (el == NULL) {
227		map_oom(module);
228		return NULL;
229	}
230
231	el->num_values = old->num_values;
232	el->values = talloc_array(el, struct ldb_val, el->num_values);
233	if (el->values == NULL) {
234		talloc_free(el);
235		map_oom(module);
236		return NULL;
237	}
238
239	el->name = talloc_strdup(el, attr_name);
240	if (el->name == NULL) {
241		talloc_free(el);
242		map_oom(module);
243		return NULL;
244	}
245
246	for (i = 0; i < el->num_values; i++) {
247		el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
248	}
249
250	return el;
251}
252
253/* Merge a remote message element into a local message. */
254static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local,
255			    struct ldb_message *remote, const char *attr_name)
256{
257	const struct ldb_map_context *data = map_get_context(module);
258	const struct ldb_map_attribute *map;
259	struct ldb_message_element *old, *el=NULL;
260	const char *remote_name = NULL;
261
262	/* We handle wildcards in ldb_msg_el_merge_wildcard */
263	if (ldb_attr_cmp(attr_name, "*") == 0) {
264		return 0;
265	}
266
267	map = map_attr_find_local(data, attr_name);
268
269	/* Unknown attribute in remote message:
270	 * skip, attribute was probably auto-generated */
271	if (map == NULL) {
272		return 0;
273	}
274
275	switch (map->type) {
276	case MAP_IGNORE:
277		break;
278	case MAP_CONVERT:
279		remote_name = map->u.convert.remote_name;
280		break;
281	case MAP_KEEP:
282		remote_name = attr_name;
283		break;
284	case MAP_RENAME:
285		remote_name = map->u.rename.remote_name;
286		break;
287	case MAP_GENERATE:
288		break;
289	}
290
291	switch (map->type) {
292	case MAP_IGNORE:
293		return 0;
294
295	case MAP_CONVERT:
296		if (map->u.convert.convert_remote == NULL) {
297			ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
298				  "Skipping attribute '%s': "
299				  "'convert_remote' not set\n",
300				  attr_name);
301			return 0;
302		}
303		/* fall through */
304	case MAP_KEEP:
305	case MAP_RENAME:
306		old = ldb_msg_find_element(remote, remote_name);
307		if (old) {
308			el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
309		} else {
310			return LDB_ERR_NO_SUCH_ATTRIBUTE;
311		}
312		break;
313
314	case MAP_GENERATE:
315		if (map->u.generate.generate_local == NULL) {
316			ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
317				  "Skipping attribute '%s': "
318				  "'generate_local' not set\n",
319				  attr_name);
320			return 0;
321		}
322
323		el = map->u.generate.generate_local(module, local, attr_name, remote);
324		if (!el) {
325			/* Generation failure is probably due to lack of source attributes */
326			return LDB_ERR_NO_SUCH_ATTRIBUTE;
327		}
328		break;
329	}
330
331	if (el == NULL) {
332		return LDB_ERR_OPERATIONS_ERROR;
333	}
334
335	return ldb_msg_replace(local, el);
336}
337
338/* Handle wildcard parts of merging a remote message element into a local message. */
339static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local,
340				     struct ldb_message *remote)
341{
342	const struct ldb_map_context *data = map_get_context(module);
343	const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
344	struct ldb_message_element *el=NULL;
345	int i, ret;
346
347	/* Perhaps we have a mapping for "*" */
348	if (map && map->type == MAP_KEEP) {
349		/* We copy everything over, and hope that anything with a
350		   more specific rule is overwritten */
351		for (i = 0; i < remote->num_elements; i++) {
352			el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name,
353						   &remote->elements[i]);
354			if (el == NULL) {
355				return LDB_ERR_OPERATIONS_ERROR;
356			}
357
358			ret = ldb_msg_replace(local, el);
359			if (ret) {
360				return ret;
361			}
362		}
363	}
364
365	/* Now walk the list of possible mappings, and apply each */
366	for (i = 0; data->attribute_maps[i].local_name; i++) {
367		ret = ldb_msg_el_merge(module, local, remote,
368				       data->attribute_maps[i].local_name);
369		if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
370			continue;
371		} else if (ret) {
372			return ret;
373		} else {
374			continue;
375		}
376	}
377
378	return 0;
379}
380
381/* Mapping messages
382 * ================ */
383
384/* Merge two local messages into a single one. */
385static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2)
386{
387	int i, ret;
388
389	for (i = 0; i < msg2->num_elements; i++) {
390		ret = ldb_msg_replace(msg1, &msg2->elements[i]);
391		if (ret) {
392			return ret;
393		}
394	}
395
396	return 0;
397}
398
399/* Merge a local and a remote message into a single local one. */
400static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local,
401				struct ldb_message *remote)
402{
403	int i, ret;
404	const char * const *attrs = ac->all_attrs;
405	if (!attrs) {
406		ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
407		if (ret) {
408			return ret;
409		}
410	}
411
412	for (i = 0; attrs && attrs[i]; i++) {
413		if (ldb_attr_cmp(attrs[i], "*") == 0) {
414			ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
415			if (ret) {
416				return ret;
417			}
418			break;
419		}
420	}
421
422	/* Try to map each attribute back;
423	 * Add to local message is possible,
424	 * Overwrite old local attribute if necessary */
425	for (i = 0; attrs && attrs[i]; i++) {
426		ret = ldb_msg_el_merge(ac->module, local, remote,
427				       attrs[i]);
428		if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
429		} else if (ret) {
430			return ret;
431		}
432	}
433
434	return 0;
435}
436
437/* Mapping search results
438 * ====================== */
439
440/* Map a search result back into the local partition. */
441static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares)
442{
443	struct ldb_message *msg;
444	struct ldb_dn *dn;
445	int ret;
446
447	/* There is no result message, skip */
448	if (ares->type != LDB_REPLY_ENTRY) {
449		return 0;
450	}
451
452	/* Create a new result message */
453	msg = ldb_msg_new(ares);
454	if (msg == NULL) {
455		map_oom(ac->module);
456		return -1;
457	}
458
459	/* Merge remote message into new message */
460	ret = ldb_msg_merge_remote(ac, msg, ares->message);
461	if (ret) {
462		talloc_free(msg);
463		return ret;
464	}
465
466	/* Create corresponding local DN */
467	dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
468	if (dn == NULL) {
469		talloc_free(msg);
470		return -1;
471	}
472	msg->dn = dn;
473
474	/* Store new message with new DN as the result */
475	talloc_free(ares->message);
476	ares->message = msg;
477
478	return 0;
479}
480
481/* Mapping parse trees
482 * =================== */
483
484/* Check whether a parse tree can safely be split in two. */
485static BOOL ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree)
486{
487	const struct ldb_parse_tree *subtree = tree;
488	BOOL negate = False;
489
490	while (subtree) {
491		switch (subtree->operation) {
492		case LDB_OP_NOT:
493			negate = !negate;
494			subtree = subtree->u.isnot.child;
495			continue;
496
497		case LDB_OP_AND:
498			return !negate;	/* if negate: False */
499
500		case LDB_OP_OR:
501			return negate;	/* if negate: True */
502
503		default:
504			return True;	/* simple parse tree */
505		}
506	}
507
508	return True;			/* no parse tree */
509}
510
511/* Collect a list of attributes required to match a given parse tree. */
512static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree)
513{
514	const char **new_attrs;
515	int i, ret;
516
517	if (tree == NULL) {
518		return 0;
519	}
520
521	switch (tree->operation) {
522	case LDB_OP_OR:
523	case LDB_OP_AND:		/* attributes stored in list of subtrees */
524		for (i = 0; i < tree->u.list.num_elements; i++) {
525			ret = ldb_parse_tree_collect_attrs(module, mem_ctx,
526							   attrs, tree->u.list.elements[i]);
527			if (ret) {
528				return ret;
529			}
530		}
531		return 0;
532
533	case LDB_OP_NOT:		/* attributes stored in single subtree */
534		return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
535
536	default:			/* single attribute in tree */
537		new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr);
538		talloc_free(*attrs);
539		*attrs = new_attrs;
540		return 0;
541	}
542
543	return -1;
544}
545
546static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
547
548/* Select a negated subtree that queries attributes in the local partition */
549static int map_subtree_select_local_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
550{
551	struct ldb_parse_tree *child;
552	int ret;
553
554	/* Prepare new tree */
555	*new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
556	if (*new == NULL) {
557		map_oom(module);
558		return -1;
559	}
560
561	/* Generate new subtree */
562	ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
563	if (ret) {
564		talloc_free(*new);
565		return ret;
566	}
567
568	/* Prune tree without subtree */
569	if (child == NULL) {
570		talloc_free(*new);
571		*new = NULL;
572		return 0;
573	}
574
575	(*new)->u.isnot.child = child;
576
577	return ret;
578}
579
580/* Select a list of subtrees that query attributes in the local partition */
581static int map_subtree_select_local_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
582{
583	int i, j, ret=0;
584
585	/* Prepare new tree */
586	*new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
587	if (*new == NULL) {
588		map_oom(module);
589		return -1;
590	}
591
592	/* Prepare list of subtrees */
593	(*new)->u.list.num_elements = 0;
594	(*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
595	if ((*new)->u.list.elements == NULL) {
596		map_oom(module);
597		talloc_free(*new);
598		return -1;
599	}
600
601	/* Generate new list of subtrees */
602	j = 0;
603	for (i = 0; i < tree->u.list.num_elements; i++) {
604		struct ldb_parse_tree *child;
605		ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
606		if (ret) {
607			talloc_free(*new);
608			return ret;
609		}
610
611		if (child) {
612			(*new)->u.list.elements[j] = child;
613			j++;
614		}
615	}
616
617	/* Prune tree without subtrees */
618	if (j == 0) {
619		talloc_free(*new);
620		*new = NULL;
621		return 0;
622	}
623
624	/* Fix subtree list size */
625	(*new)->u.list.num_elements = j;
626	(*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
627
628	return ret;
629}
630
631/* Select a simple subtree that queries attributes in the local partition */
632static int map_subtree_select_local_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
633{
634	/* Prepare new tree */
635	*new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
636	if (*new == NULL) {
637		map_oom(module);
638		return -1;
639	}
640
641	return 0;
642}
643
644/* Select subtrees that query attributes in the local partition */
645static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
646{
647	const struct ldb_map_context *data = map_get_context(module);
648
649	if (tree == NULL) {
650		return 0;
651	}
652
653	if (tree->operation == LDB_OP_NOT) {
654		return map_subtree_select_local_not(module, mem_ctx, new, tree);
655	}
656
657	if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
658		return map_subtree_select_local_list(module, mem_ctx, new, tree);
659	}
660
661	if (map_attr_check_remote(data, tree->u.equality.attr)) {
662		*new = NULL;
663		return 0;
664	}
665
666	return map_subtree_select_local_simple(module, mem_ctx, new, tree);
667}
668
669static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
670
671/* Collect a negated subtree that queries attributes in the remote partition */
672static int map_subtree_collect_remote_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
673{
674	struct ldb_parse_tree *child;
675	int ret;
676
677	/* Prepare new tree */
678	*new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
679	if (*new == NULL) {
680		map_oom(module);
681		return -1;
682	}
683
684	/* Generate new subtree */
685	ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
686	if (ret) {
687		talloc_free(*new);
688		return ret;
689	}
690
691	/* Prune tree without subtree */
692	if (child == NULL) {
693		talloc_free(*new);
694		*new = NULL;
695		return 0;
696	}
697
698	(*new)->u.isnot.child = child;
699
700	return ret;
701}
702
703/* Collect a list of subtrees that query attributes in the remote partition */
704static int map_subtree_collect_remote_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
705{
706	int i, j, ret=0;
707
708	/* Prepare new tree */
709	*new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
710	if (*new == NULL) {
711		map_oom(module);
712		return -1;
713	}
714
715	/* Prepare list of subtrees */
716	(*new)->u.list.num_elements = 0;
717	(*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
718	if ((*new)->u.list.elements == NULL) {
719		map_oom(module);
720		talloc_free(*new);
721		return -1;
722	}
723
724	/* Generate new list of subtrees */
725	j = 0;
726	for (i = 0; i < tree->u.list.num_elements; i++) {
727		struct ldb_parse_tree *child;
728		ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
729		if (ret) {
730			talloc_free(*new);
731			return ret;
732		}
733
734		if (child) {
735			(*new)->u.list.elements[j] = child;
736			j++;
737		}
738	}
739
740	/* Prune tree without subtrees */
741	if (j == 0) {
742		talloc_free(*new);
743		*new = NULL;
744		return 0;
745	}
746
747	/* Fix subtree list size */
748	(*new)->u.list.num_elements = j;
749	(*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
750
751	return ret;
752}
753
754/* Collect a simple subtree that queries attributes in the remote partition */
755int 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)
756{
757	const char *attr;
758
759	/* Prepare new tree */
760	*new = talloc(mem_ctx, struct ldb_parse_tree);
761	if (*new == NULL) {
762		map_oom(module);
763		return -1;
764	}
765	**new = *tree;
766
767	if (map->type == MAP_KEEP) {
768		/* Nothing to do here */
769		return 0;
770	}
771
772	/* Store attribute and value in new tree */
773	switch (tree->operation) {
774	case LDB_OP_PRESENT:
775		attr = map_attr_map_local(*new, map, tree->u.present.attr);
776		(*new)->u.present.attr = attr;
777		break;
778	case LDB_OP_SUBSTRING:
779	{
780		attr = map_attr_map_local(*new, map, tree->u.substring.attr);
781		(*new)->u.substring.attr = attr;
782		break;
783	}
784	case LDB_OP_EQUALITY:
785		attr = map_attr_map_local(*new, map, tree->u.equality.attr);
786		(*new)->u.equality.attr = attr;
787		break;
788	case LDB_OP_LESS:
789	case LDB_OP_GREATER:
790	case LDB_OP_APPROX:
791		attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
792		(*new)->u.comparison.attr = attr;
793		break;
794	case LDB_OP_EXTENDED:
795		attr = map_attr_map_local(*new, map, tree->u.extended.attr);
796		(*new)->u.extended.attr = attr;
797		break;
798	default:			/* unknown kind of simple subtree */
799		talloc_free(*new);
800		return -1;
801	}
802
803	if (attr == NULL) {
804		talloc_free(*new);
805		*new = NULL;
806		return 0;
807	}
808
809	if (map->type == MAP_RENAME) {
810		/* Nothing more to do here, the attribute has been renamed */
811		return 0;
812	}
813
814	/* Store attribute and value in new tree */
815	switch (tree->operation) {
816	case LDB_OP_PRESENT:
817		break;
818	case LDB_OP_SUBSTRING:
819	{
820		int i;
821		/* Map value */
822		(*new)->u.substring.chunks = NULL;
823		for (i=0; tree->u.substring.chunks[i]; i++) {
824			(*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2);
825			if (!(*new)->u.substring.chunks) {
826				talloc_free(*new);
827				*new = NULL;
828				return 0;
829			}
830			(*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
831			if (!(*new)->u.substring.chunks[i]) {
832				talloc_free(*new);
833				*new = NULL;
834				return 0;
835			}
836			*(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]);
837			(*new)->u.substring.chunks[i+1] = NULL;
838		}
839		break;
840	}
841	case LDB_OP_EQUALITY:
842		(*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
843		break;
844	case LDB_OP_LESS:
845	case LDB_OP_GREATER:
846	case LDB_OP_APPROX:
847		(*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
848		break;
849	case LDB_OP_EXTENDED:
850		(*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value);
851		(*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id);
852		break;
853	default:			/* unknown kind of simple subtree */
854		talloc_free(*new);
855		return -1;
856	}
857
858	return 0;
859}
860
861/* Collect subtrees that query attributes in the remote partition */
862static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
863{
864	const struct ldb_map_context *data = map_get_context(module);
865	const struct ldb_map_attribute *map;
866
867	if (tree == NULL) {
868		return 0;
869	}
870
871	if (tree->operation == LDB_OP_NOT) {
872		return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
873	}
874
875	if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
876		return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
877	}
878
879	if (!map_attr_check_remote(data, tree->u.equality.attr)) {
880		*new = NULL;
881		return 0;
882	}
883
884	map = map_attr_find_local(data, tree->u.equality.attr);
885	if (map->convert_operator) {
886		return map->convert_operator(module, mem_ctx, new, tree);
887	}
888
889	if (map->type == MAP_GENERATE) {
890		ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
891			  "Skipping attribute '%s': "
892			  "'convert_operator' not set\n",
893			  tree->u.equality.attr);
894		*new = NULL;
895		return 0;
896	}
897
898	return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map);
899}
900
901/* Split subtrees that query attributes in the local partition from
902 * those that query the remote partition. */
903static 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)
904{
905	int ret;
906
907	*local_tree = NULL;
908	*remote_tree = NULL;
909
910	/* No original tree */
911	if (tree == NULL) {
912		return 0;
913	}
914
915	/* Generate local tree */
916	ret = map_subtree_select_local(module, local_ctx, local_tree, tree);
917	if (ret) {
918		return ret;
919	}
920
921	/* Generate remote tree */
922	ret = map_subtree_collect_remote(module, remote_ctx, remote_tree, tree);
923	if (ret) {
924		talloc_free(*local_tree);
925		return ret;
926	}
927
928	return 0;
929}
930
931/* Collect a list of attributes required either explicitly from a
932 * given list or implicitly  from a given parse tree; split the
933 * collected list into local and remote parts. */
934static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac,
935					   const char * const *search_attrs,
936					   const struct ldb_parse_tree *tree)
937{
938	void *tmp_ctx;
939	const char **tree_attrs;
940	const char **remote_attrs;
941	const char **local_attrs;
942	int ret;
943
944	/* Clear initial lists of partitioned attributes */
945
946	/* Clear initial lists of partitioned attributes */
947
948	/* There is no tree, just partition the searched attributes */
949	if (tree == NULL) {
950		ret = map_attrs_partition(module, ac,
951					  &local_attrs, &remote_attrs, search_attrs);
952		if (ret == 0) {
953			ac->local_attrs = local_attrs;
954			ac->remote_attrs = remote_attrs;
955			ac->all_attrs = search_attrs;
956		}
957		return ret;
958	}
959
960	/* Create context for temporary memory */
961	tmp_ctx = talloc_new(ac);
962	if (tmp_ctx == NULL) {
963		goto oom;
964	}
965
966	/* Prepare list of attributes from tree */
967	tree_attrs = talloc_array(tmp_ctx, const char *, 1);
968	if (tree_attrs == NULL) {
969		talloc_free(tmp_ctx);
970		goto oom;
971	}
972	tree_attrs[0] = NULL;
973
974	/* Collect attributes from tree */
975	ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
976	if (ret) {
977		goto done;
978	}
979
980	/* Merge attributes from search operation */
981	ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
982	if (ret) {
983		goto done;
984	}
985
986	/* Split local from remote attributes */
987	ret = map_attrs_partition(module, ac, &local_attrs,
988				  &remote_attrs, tree_attrs);
989
990	if (ret == 0) {
991		ac->local_attrs = local_attrs;
992		ac->remote_attrs = remote_attrs;
993		talloc_steal(ac, tree_attrs);
994		ac->all_attrs = tree_attrs;
995	}
996done:
997	/* Free temporary memory */
998	talloc_free(tmp_ctx);
999	return ret;
1000
1001oom:
1002	map_oom(module);
1003	return -1;
1004}
1005
1006
1007/* Outbound requests: search
1008 * ========================= */
1009
1010/* Pass a merged search result up the callback chain. */
1011int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, struct ldb_reply *ares)
1012{
1013	int i;
1014
1015	/* No callback registered, stop */
1016	if (req->callback == NULL) {
1017		return LDB_SUCCESS;
1018	}
1019
1020	/* Only records need special treatment */
1021	if (ares->type != LDB_REPLY_ENTRY) {
1022		return req->callback(ldb, req->context, ares);
1023	}
1024
1025	/* Merged result doesn't match original query, skip */
1026	if (!ldb_match_msg(ldb, ares->message, req->op.search.tree, req->op.search.base, req->op.search.scope)) {
1027		ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
1028			  "Skipping record '%s': "
1029			  "doesn't match original search\n",
1030			  ldb_dn_linearize(ldb, ares->message->dn));
1031		return LDB_SUCCESS;
1032	}
1033
1034	/* Limit result to requested attrs */
1035	if ((req->op.search.attrs) && (!ldb_attr_in_list(req->op.search.attrs, "*"))) {
1036		for (i = 0; i < ares->message->num_elements; ) {
1037			struct ldb_message_element *el = &ares->message->elements[i];
1038			if (!ldb_attr_in_list(req->op.search.attrs, el->name)) {
1039				ldb_msg_remove_element(ares->message, el);
1040			} else {
1041				i++;
1042			}
1043		}
1044	}
1045
1046	return req->callback(ldb, req->context, ares);
1047}
1048
1049/* Merge the remote and local parts of a search result. */
1050int map_local_merge_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
1051{
1052	struct map_search_context *sc;
1053	int ret;
1054
1055	if (context == NULL || ares == NULL) {
1056		ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
1057						       "NULL Context or Result in `map_local_merge_callback`"));
1058		return LDB_ERR_OPERATIONS_ERROR;
1059	}
1060
1061	sc = talloc_get_type(context, struct map_search_context);
1062
1063	switch (ares->type) {
1064	case LDB_REPLY_ENTRY:
1065		/* We have already found a local record */
1066		if (sc->local_res) {
1067			ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
1068							       "Too many results to base search for local entry"));
1069			talloc_free(ares);
1070			return LDB_ERR_OPERATIONS_ERROR;
1071		}
1072
1073		/* Store local result */
1074		sc->local_res = ares;
1075
1076		/* Merge remote into local message */
1077		ret = ldb_msg_merge_local(sc->ac->module, ares->message, sc->remote_res->message);
1078		if (ret) {
1079			talloc_free(ares);
1080			return LDB_ERR_OPERATIONS_ERROR;
1081		}
1082
1083		return map_up_callback(ldb, sc->ac->orig_req, ares);
1084
1085	case LDB_REPLY_DONE:
1086		/* No local record found, continue with remote record */
1087		if (sc->local_res == NULL) {
1088			return map_up_callback(ldb, sc->ac->orig_req, sc->remote_res);
1089		}
1090		return LDB_SUCCESS;
1091
1092	default:
1093		ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
1094						       "Unexpected result type in base search for local entry"));
1095		talloc_free(ares);
1096		return LDB_ERR_OPERATIONS_ERROR;
1097	}
1098}
1099
1100/* Search the local part of a remote search result. */
1101int map_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
1102{
1103	struct map_context *ac;
1104	struct map_search_context *sc;
1105	struct ldb_request *req;
1106	int ret;
1107
1108	if (context == NULL || ares == NULL) {
1109		ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
1110						       "NULL Context or Result in `map_remote_search_callback`"));
1111		return LDB_ERR_OPERATIONS_ERROR;
1112	}
1113
1114	ac = talloc_get_type(context, struct map_context);
1115
1116	/* It's not a record, stop searching */
1117	if (ares->type != LDB_REPLY_ENTRY) {
1118		return map_up_callback(ldb, ac->orig_req, ares);
1119	}
1120
1121	/* Map result record into a local message */
1122	ret = map_reply_remote(ac, ares);
1123	if (ret) {
1124		talloc_free(ares);
1125		return LDB_ERR_OPERATIONS_ERROR;
1126	}
1127
1128	/* There is no local db, stop searching */
1129	if (!map_check_local_db(ac->module)) {
1130		return map_up_callback(ldb, ac->orig_req, ares);
1131	}
1132
1133	/* Prepare local search context */
1134	sc = map_init_search_context(ac, ares);
1135	if (sc == NULL) {
1136		talloc_free(ares);
1137		return LDB_ERR_OPERATIONS_ERROR;
1138	}
1139
1140	/* Prepare local search request */
1141	/* TODO: use GUIDs here instead? */
1142
1143	ac->search_reqs = talloc_realloc(ac, ac->search_reqs, struct ldb_request *, ac->num_searches + 2);
1144	if (ac->search_reqs == NULL) {
1145		talloc_free(ares);
1146		return LDB_ERR_OPERATIONS_ERROR;
1147	}
1148
1149	ac->search_reqs[ac->num_searches]
1150		= req = map_search_base_req(ac, ares->message->dn,
1151					    NULL, NULL, sc, map_local_merge_callback);
1152	if (req == NULL) {
1153		talloc_free(sc);
1154		talloc_free(ares);
1155		return LDB_ERR_OPERATIONS_ERROR;
1156	}
1157	ac->num_searches++;
1158	ac->search_reqs[ac->num_searches] = NULL;
1159
1160	return ldb_next_request(ac->module, req);
1161}
1162
1163/* Search a record. */
1164int map_search(struct ldb_module *module, struct ldb_request *req)
1165{
1166	struct ldb_handle *h;
1167	struct map_context *ac;
1168	struct ldb_parse_tree *local_tree, *remote_tree;
1169	int ret;
1170
1171	const char *wildcard[] = { "*", NULL };
1172	const char * const *attrs;
1173
1174	/* Do not manipulate our control entries */
1175	if (ldb_dn_is_special(req->op.search.base))
1176		return ldb_next_request(module, req);
1177
1178	/* No mapping requested, skip to next module */
1179	if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
1180		return ldb_next_request(module, req);
1181	}
1182
1183	/* TODO: How can we be sure about which partition we are
1184	 *	 targetting when there is no search base? */
1185
1186	/* Prepare context and handle */
1187	h = map_init_handle(req, module);
1188	if (h == NULL) {
1189		return LDB_ERR_OPERATIONS_ERROR;
1190	}
1191	ac = talloc_get_type(h->private_data, struct map_context);
1192
1193	ac->search_reqs = talloc_array(ac, struct ldb_request *, 2);
1194	if (ac->search_reqs == NULL) {
1195		talloc_free(h);
1196		return LDB_ERR_OPERATIONS_ERROR;
1197	}
1198	ac->num_searches = 1;
1199	ac->search_reqs[1] = NULL;
1200
1201	/* Prepare the remote operation */
1202	ac->search_reqs[0] = talloc(ac, struct ldb_request);
1203	if (ac->search_reqs[0] == NULL) {
1204		goto oom;
1205	}
1206
1207	*(ac->search_reqs[0]) = *req;	/* copy the request */
1208
1209	ac->search_reqs[0]->handle = h;	/* return our own handle to deal with this call */
1210
1211	ac->search_reqs[0]->context = ac;
1212	ac->search_reqs[0]->callback = map_remote_search_callback;
1213
1214	/* It is easier to deal with the two different ways of
1215	 * expressing the wildcard in the same codepath */
1216	attrs = req->op.search.attrs;
1217	if (attrs == NULL) {
1218		attrs = wildcard;
1219	}
1220
1221	/* Split local from remote attrs */
1222	ret = map_attrs_collect_and_partition(module, ac,
1223					      attrs, req->op.search.tree);
1224	if (ret) {
1225		goto failed;
1226	}
1227
1228	ac->search_reqs[0]->op.search.attrs = ac->remote_attrs;
1229
1230	/* Split local from remote tree */
1231	ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0],
1232				       &local_tree, &remote_tree,
1233				       req->op.search.tree);
1234	if (ret) {
1235		goto failed;
1236	}
1237
1238	if (((local_tree != NULL) && (remote_tree != NULL)) &&
1239	    (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
1240		/* The query can't safely be split, enumerate the remote partition */
1241		local_tree = NULL;
1242		remote_tree = NULL;
1243	}
1244
1245	if (local_tree == NULL) {
1246		/* Construct default local parse tree */
1247		local_tree = talloc_zero(ac, struct ldb_parse_tree);
1248		if (local_tree == NULL) {
1249			map_oom(ac->module);
1250			goto failed;
1251		}
1252
1253		local_tree->operation = LDB_OP_PRESENT;
1254		local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
1255	}
1256	if (remote_tree == NULL) {
1257		/* Construct default remote parse tree */
1258		remote_tree = ldb_parse_tree(ac->search_reqs[0], NULL);
1259		if (remote_tree == NULL) {
1260			goto failed;
1261		}
1262	}
1263
1264	ac->local_tree = local_tree;
1265	ac->search_reqs[0]->op.search.tree = remote_tree;
1266
1267	ldb_set_timeout_from_prev_req(module->ldb, req, ac->search_reqs[0]);
1268
1269	h->state = LDB_ASYNC_INIT;
1270	h->status = LDB_SUCCESS;
1271
1272	ac->step = MAP_SEARCH_REMOTE;
1273
1274	ret = ldb_next_remote_request(module, ac->search_reqs[0]);
1275	if (ret == LDB_SUCCESS) {
1276		req->handle = h;
1277	}
1278	return ret;
1279
1280oom:
1281	map_oom(module);
1282failed:
1283	talloc_free(h);
1284	return LDB_ERR_OPERATIONS_ERROR;
1285}
1286